using System; using System.Collections.Generic; using System.Linq; using Moserware.Numerics; using Moserware.Skills.FactorGraphs; using Moserware.Skills.TrueSkill.Factors; namespace Moserware.Skills.TrueSkill.Layers { // The whole purpose of this is to do a loop on the bottom internal class IteratedTeamDifferencesInnerLayer : TrueSkillFactorGraphLayer , GaussianWeightedSumFactor, Variable> { private readonly TeamDifferencesComparisonLayer _TeamDifferencesComparisonLayer; private readonly TeamPerformancesToTeamPerformanceDifferencesLayer _TeamPerformancesToTeamPerformanceDifferencesLayer; public IteratedTeamDifferencesInnerLayer(TrueSkillFactorGraph parentGraph, TeamPerformancesToTeamPerformanceDifferencesLayer teamPerformancesToPerformanceDifferences, TeamDifferencesComparisonLayer teamDifferencesComparisonLayer) : base(parentGraph) { _TeamPerformancesToTeamPerformanceDifferencesLayer = teamPerformancesToPerformanceDifferences; _TeamDifferencesComparisonLayer = teamDifferencesComparisonLayer; } public override IEnumerable> UntypedFactors { get { return _TeamPerformancesToTeamPerformanceDifferencesLayer.UntypedFactors.Concat( _TeamDifferencesComparisonLayer.UntypedFactors); } } public override void BuildLayer() { _TeamPerformancesToTeamPerformanceDifferencesLayer.SetRawInputVariablesGroups(InputVariablesGroups); _TeamPerformancesToTeamPerformanceDifferencesLayer.BuildLayer(); _TeamDifferencesComparisonLayer.SetRawInputVariablesGroups( _TeamPerformancesToTeamPerformanceDifferencesLayer.GetRawOutputVariablesGroups()); _TeamDifferencesComparisonLayer.BuildLayer(); } public override Schedule CreatePriorSchedule() { Schedule loop = null; switch (InputVariablesGroups.Count) { case 0: case 1: throw new InvalidOperationException(); case 2: loop = CreateTwoTeamInnerPriorLoopSchedule(); break; default: loop = CreateMultipleTeamInnerPriorLoopSchedule(); break; } // When dealing with differences, there are always (n-1) differences, so add in the 1 int totalTeamDifferences = _TeamPerformancesToTeamPerformanceDifferencesLayer.LocalFactors.Count; int totalTeams = totalTeamDifferences + 1; var innerSchedule = new ScheduleSequence( "inner schedule", new[] { loop, new ScheduleStep( "teamPerformanceToPerformanceDifferenceFactors[0] @ 1", _TeamPerformancesToTeamPerformanceDifferencesLayer.LocalFactors[0], 1), new ScheduleStep( String.Format("teamPerformanceToPerformanceDifferenceFactors[teamTeamDifferences = {0} - 1] @ 2", totalTeamDifferences), _TeamPerformancesToTeamPerformanceDifferencesLayer.LocalFactors[totalTeamDifferences - 1], 2) } ); return innerSchedule; } private Schedule CreateTwoTeamInnerPriorLoopSchedule() { return ScheduleSequence( new[] { new ScheduleStep( "send team perf to perf differences", _TeamPerformancesToTeamPerformanceDifferencesLayer.LocalFactors[0], 0), new ScheduleStep( "send to greater than or within factor", _TeamDifferencesComparisonLayer.LocalFactors[0], 0) }, "loop of just two teams inner sequence"); } private Schedule CreateMultipleTeamInnerPriorLoopSchedule() { int totalTeamDifferences = _TeamPerformancesToTeamPerformanceDifferencesLayer.LocalFactors.Count; var forwardScheduleList = new List>(); for (int i = 0; i < totalTeamDifferences - 1; i++) { Schedule currentForwardSchedulePiece = ScheduleSequence( new Schedule[] { new ScheduleStep( String.Format("team perf to perf diff {0}", i), _TeamPerformancesToTeamPerformanceDifferencesLayer.LocalFactors[i], 0), new ScheduleStep( String.Format("greater than or within result factor {0}", i), _TeamDifferencesComparisonLayer.LocalFactors[i], 0), new ScheduleStep( String.Format("team perf to perf diff factors [{0}], 2", i), _TeamPerformancesToTeamPerformanceDifferencesLayer.LocalFactors[i], 2) }, "current forward schedule piece {0}", i); forwardScheduleList.Add(currentForwardSchedulePiece); } var forwardSchedule = new ScheduleSequence( "forward schedule", forwardScheduleList); var backwardScheduleList = new List>(); for (int i = 0; i < totalTeamDifferences - 1; i++) { var currentBackwardSchedulePiece = new ScheduleSequence( "current backward schedule piece", new Schedule[] { new ScheduleStep( String.Format("teamPerformanceToPerformanceDifferenceFactors[totalTeamDifferences - 1 - {0}] @ 0", i), _TeamPerformancesToTeamPerformanceDifferencesLayer.LocalFactors[ totalTeamDifferences - 1 - i], 0), new ScheduleStep( String.Format("greaterThanOrWithinResultFactors[totalTeamDifferences - 1 - {0}] @ 0", i), _TeamDifferencesComparisonLayer.LocalFactors[totalTeamDifferences - 1 - i], 0), new ScheduleStep( String.Format("teamPerformanceToPerformanceDifferenceFactors[totalTeamDifferences - 1 - {0}] @ 1", i), _TeamPerformancesToTeamPerformanceDifferencesLayer.LocalFactors[ totalTeamDifferences - 1 - i], 1) } ); backwardScheduleList.Add(currentBackwardSchedulePiece); } var backwardSchedule = new ScheduleSequence( "backward schedule", backwardScheduleList); var forwardBackwardScheduleToLoop = new ScheduleSequence( "forward Backward Schedule To Loop", new Schedule[] { forwardSchedule, backwardSchedule }); const double initialMaxDelta = 0.0001; var loop = new ScheduleLoop( String.Format("loop with max delta of {0}", initialMaxDelta), forwardBackwardScheduleToLoop, initialMaxDelta); return loop; } } }