package geniusweb.protocol.tournament.allpermutationslearn;
import java.math.BigInteger;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import geniusweb.actions.FileLocation;
import geniusweb.protocol.session.SessionSettings;
import geniusweb.protocol.session.TeamInfo;
import geniusweb.protocol.session.learn.LearnSettings;
import geniusweb.protocol.tournament.ProfileList;
import geniusweb.protocol.tournament.Team;
import geniusweb.protocol.tournament.TournamentProtocol;
import geniusweb.protocol.tournament.allpermutations.AllPermutationsSettings;
import geniusweb.references.Parameters;
import geniusweb.references.PartyWithProfile;
import geniusweb.references.ProfileRef;
import tudelft.utilities.immutablelist.FixedList;
import tudelft.utilities.immutablelist.ImmutableList;
import tudelft.utilities.immutablelist.JoinedList;
import tudelft.utilities.immutablelist.MapThreadList;
import tudelft.utilities.logging.Reporter;
/**
* Almost the same as AllPermutationsSettings.
*
* The only additional field is the additional learnTime. This has a maximum to
* the maximum number of sessions, {@link #MAX_SESSIONS}. This is because we
* need to store all the {@link FileLocation}s explicitly.
*
* Only the first team member is actually getting the learn time.
*
* We assume that all parties have the proper persistentstate parameter already.
* This is assumed to be set in the {@link Team} settings
*/
public class AllPermutationsLearnSettings extends AllPermutationsSettings {
/**
* MAX_SESSIONS is the maximum number of sessions in a tournament. It is
* depending on a number of factors:
*
* - The memory use to store all UUIDs for all parties
*
- The MAX_MESSAGE_SIZE of a websocket message.
*
* The MAX_MESSAGE_SIZE of the partyserver currently is 20MB. A single UUID
* is about 45 bytes including double quotes and commas
*
*/
private final static int MAX_SESSIONS = 400000;
private final static ObjectMapper jackson = new ObjectMapper();
private final LearnSettings learnSettings;
/**
*
* @param teams a list of {@link Team}s. Must contain at least
* {@link #teamsPerSession} elements. The
* {@link #teamsPerSession} must match the protocol:
* (SAOP:1, SHAOP:2)
* @param reuseTeams if true, we use PermutationsWithReturn, if false
* we use PermutationsWithoutReturn to create the
* teams.
* @param plists list of available {@link ProfileList}s to be
* permutated over the teams. Each
* {@link ProfileList} must contain
* {@link #teamsPerSession} elements.
* @param teamsPerSession number of parties per session, must be at least 2.
* @param sesettings The generic {@link SessionSettings}.
* {@link SessionSettings#with(TeamInfo)} will be
* used to add the required {@link TeamInfo}s. All
* settings must contain a 'persistentstate'
* parameter with a {@link FileLocation}.
* @param nTournaments the number of times the tournament should be run.
* @param learnSet the {@link LearnSettings} to be used for the
* learning phase. The participants list should be
* empty as this will be filled up from the teams
* provided above. Only the deadline is used.
*/
@JsonCreator
public AllPermutationsLearnSettings(@JsonProperty("teams") List teams,
@JsonProperty("profileslists") List plists,
@JsonProperty("reuseTeams") boolean reuseTeams,
@JsonProperty("teamsPerSession") int teamsPerSession,
@JsonProperty("sessionsettings") SessionSettings sesettings,
@JsonProperty("numberTournaments") int nTournaments,
@JsonProperty("learnSettings") LearnSettings learnSet) {
super(teams, plists, reuseTeams, teamsPerSession, sesettings,
nTournaments);
this.learnSettings = learnSet;
}
@Override
public TournamentProtocol getProtocol(Reporter logger) {
AllPermutationsLearnState state = new AllPermutationsLearnState(this,
permutations(), Collections.emptyList());
return new AllPermutationsLearnProtocol(state, logger);
}
@Override
public Double getMaxRunTime() {
return super.permutations().size().doubleValue()
* (sessionsettings.getMaxRunTime() + 2d)
+ learnSettings.getMaxRunTime();
}
/**
* @return {@link ImmutableList} containing all {@link SessionSettings} for
* all Sessions in the correct order.
*/
@Override
public ImmutableList permutations() {
ImmutableList allsessionsettings = super.permutations();
if (allsessionsettings.size()
.compareTo(BigInteger.valueOf(MAX_SESSIONS)) > 0)
throw new IllegalArgumentException(
"learn-tournament exceeds max number of sessions "
+ MAX_SESSIONS);
FixedList> filelocs = createFileLocations(
allsessionsettings.size().longValue());
ImmutableList> partylistlist;
ImmutableList partieslist = new FixedList(teams);
ImmutableList profileslist = new FixedList(
profileslists);
partylistlist = getParticipants(partieslist, profileslist,
teamsPerSession, reuseTeams);
ImmutableList settings = new MapThreadList<>(
(parties, flocs) -> createSetting(parties, flocs),
partylistlist, filelocs);
return new JoinedList(settings,
getLearnSessions(filelocs, partylistlist));
}
@Override
public String toString() {
return "AllPermutationsLearnSettings[" + contentString() + ","
+ learnSettings + "]";
}
/**
*
* @param numsessions the number of sessions in the tournament
* @return A list of list of {@link FileLocation}s. The outer list has one
* entry for each session, the inner list has one
* {@link FileLocation} per party.
*/
private FixedList> createFileLocations(
long numsessions) {
// like before, but all sessions need a new negotiationdata
List> filelocations = new ArrayList<>();
for (long sessionnr = 0; sessionnr < numsessions; sessionnr++) {
List locs = new ArrayList<>();
for (int teamnr = 0; teamnr < teamsPerSession; teamnr++) {
locs.add(new FileLocation());
}
filelocations.add(new FixedList<>(locs));
}
FixedList> filelocs = new FixedList<>(
filelocations);
return filelocs;
}
/**
* @param allsessionsettings the 'traditional session settings.
* @param filelocs the {@link FileLocation}s for each session, for
* each party
* @param partylistlist the lists of all teams for the sessions, with
* unaltered parameters matching the
* {@link #teams} list
* @return the final sessions, doing learning for all parties. In this
* session, the number of parties may be larger than
* {@link #teamsPerSession}. Learning may be spread over multiple
* sessions, although we don't do this currently.
*/
private ImmutableList getLearnSessions(
FixedList> filelocs,
ImmutableList> partylistlist) {
try {
ProfileRef NOPROFILE = new ProfileRef("not://aprofile");
SessionSettings session = learnSettings;
// add all the teams, with updated parameters, to the session
for (Team team : teams) {
List files = getNegoData(team, filelocs,
partylistlist);
// Tricky: correct parameter is list of UUID strings
List filesstrings = files.stream()
.map(file -> file.getUUIDString())
.collect(Collectors.toList());
Parameters parameters = new Parameters().with("negotiationdata",
filesstrings);
// add all the FileLocations and NOPROFILE to all team members
List teaminfo = team.getParties().stream()
.map(pwp -> new PartyWithProfile(pwp.with(parameters),
NOPROFILE))
.collect(Collectors.toList());
session = session.with(new TeamInfo(teaminfo));
}
return new FixedList(Arrays.asList(session));
} catch (URISyntaxException e) {
throw new RuntimeException("Failed creating learn session", e);
}
}
/**
* @param team the team for which the {@link FileLocation}s are needed
* @param filelocs the used {@link FileLocation}s for all sessions, all
* teams.
* @param TeamInfo the TeamInfo used for each session, team. Same dimensions
* as filelocs
* @return the list of FileLocations that were provided to the given team in
* the negotiation sessions.
*/
private List getNegoData(Team team,
FixedList> filelocs,
ImmutableList> partylistlist) {
List locs = new ArrayList<>();
for (long sessionnr = 0; sessionnr < filelocs.size()
.longValue(); sessionnr++) {
for (int teamnr = 0; teamnr < teamsPerSession; teamnr++) {
if (team.equals(
partylistlist.get(sessionnr).get(teamnr).getTeam()))
locs.add(filelocs.get(sessionnr).get(teamnr));
}
}
return locs;
}
/**
*
* @param partyproflist a list of {@link PartyWithProfile} settings. Now,
* each party gets a new negotiationdata object in
* every session.
* @param locs the FileLocations for the negotiationdata for all
* teams
* @return {@link SessionSettings}, with each party parameters extended with
* its {@link FileLocation}
*/
private SessionSettings createSetting(ImmutableList partyproflist,
ImmutableList locs) {
SessionSettings settings = sessionsettings;
for (int teamnr = 0; teamnr < partyproflist.size()
.intValue(); teamnr++) {
Parameters extraparams = new Parameters().with("negotiationdata",
Arrays.asList(locs.get(teamnr)));
TeamInfo teaminfo = partyproflist.get(teamnr).with(extraparams);
settings = settings.with(teaminfo);
}
return settings;
}
}