Updated day 12 WIP performance refactor
- Added combinations calculation directly to the multi-index enumerable (TValidationPositionOffsets) and added new intermediate derived class TAccumulatedCombinationsMultiIndexStrategy to make this reusable for the other enumerables - Removed TBinomialCoefficientCache instances and used new global instance instead - Renamed TValidationToDamageAssignments to TDamageToValidationAssignments
This commit is contained in:
parent
3f7fb4a548
commit
ec6928679a
|
@ -41,6 +41,7 @@ const
|
|||
|
||||
type
|
||||
TIntegerList = specialize TList<Integer>;
|
||||
TInt64Array = array of Int64;
|
||||
|
||||
implementation
|
||||
|
||||
|
|
|
@ -63,9 +63,9 @@ type
|
|||
end;
|
||||
TBlocks = specialize TObjectList<TBlock>;
|
||||
|
||||
{ TValidationToDamageAssignments }
|
||||
{ TDamageToValidationAssignments }
|
||||
|
||||
TValidationToDamageAssignments = class(TEnumerableMultiIndexStrategy)
|
||||
TDamageToValidationAssignments = class(TEnumerableMultiIndexStrategy)
|
||||
private
|
||||
FValidation: TIntegerList;
|
||||
FValidationLengths: TValidationLengths;
|
||||
|
@ -92,14 +92,34 @@ type
|
|||
|
||||
TValidationPositionInfos = specialize TList<TValidationPositionInfo>;
|
||||
|
||||
TConditionRecord = class;
|
||||
|
||||
{ TAccumulatedCombinationsMultiIndexStrategy }
|
||||
|
||||
TAccumulatedCombinationsMultiIndexStrategy = class(TEnumerableMultiIndexStrategy)
|
||||
private
|
||||
FAccumulatedCombinations: TInt64Array;
|
||||
protected
|
||||
function CalcCombinations(constref ACurrentIndexArray: TIndexArray; const ACurrentIndex: Integer): Int64; virtual;
|
||||
abstract;
|
||||
function UpdateCombinations(const AValidationResult: TIndexValidationResult; constref ACurrentIndexArray:
|
||||
TIndexArray; const ACurrentIndex: Integer): TIndexValidationResult;
|
||||
public
|
||||
function GetCombinations: Int64;
|
||||
end;
|
||||
|
||||
{ TValidationPositionOffsets }
|
||||
|
||||
TValidationPositionOffsets = class(TEnumerableMultiIndexStrategy)
|
||||
TValidationPositionOffsets = class(TAccumulatedCombinationsMultiIndexStrategy)
|
||||
private
|
||||
FValidation: TIntegerList;
|
||||
FConditionRecord: TConditionRecord;
|
||||
FPositionInfos: TValidationPositionInfos;
|
||||
FBlockLength, FStartIndex, FStopIndex: Integer;
|
||||
protected
|
||||
function CalcCombinations(constref ACurrentIndexArray: TIndexArray; const ACurrentIndex: Integer): Int64; override;
|
||||
public
|
||||
constructor Create(constref AValidation: TIntegerList; constref APositionInfos: TValidationPositionInfos);
|
||||
constructor Create(constref AConditionRecord: TConditionRecord; constref APositionInfos: TValidationPositionInfos;
|
||||
const ABlockLength, AStartIndex, AStopIndex: Integer);
|
||||
function GetCardinality: Integer; override;
|
||||
function TryGetStartIndexValue(constref ACurrentIndexArray: TIndexArray; const ACurrentIndex: Integer;
|
||||
out AStartIndexValue: Integer): Boolean; override;
|
||||
|
@ -111,7 +131,6 @@ type
|
|||
|
||||
TConditionRecord = class
|
||||
private
|
||||
FBinomialCoefficients: TBinomialCoefficientCache;
|
||||
FValidation: TIntegerList;
|
||||
// List of non-empty, maximum-length parts of the pattern without operational springs ("blocks").
|
||||
FBlocks: TBlocks;
|
||||
|
@ -129,17 +148,13 @@ type
|
|||
function CalcCombinationsBlockSingleValidation(constref ABlock: TBlock; const AIndex: Integer): Int64;
|
||||
function CalcCombinationsBlockMultiValidations(constref ABlock: TBlock; constref AIndices: TIndexArray;
|
||||
const AStartIndex, AStopIndex: Integer): Int64;
|
||||
function CalcCombinationsBlockAssignedValidations(const ABlockLength: Integer; constref APositionInfos:
|
||||
TValidationPositionInfos; constref AOffsets: TIndexArray; const AStartIndex, AStopIndex: Integer): Int64;
|
||||
function CalcCombinationsWildcardSequence(const ASequenceLength, AStartIndex, AStopIndex: Integer): Int64;
|
||||
public
|
||||
constructor Create(constref ABinomialCoefficients: TBinomialCoefficientCache);
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
// Adds all non-empty, maximum-length parts of the pattern without operational springs ("blocks").
|
||||
procedure AddBlocks(const APattern: string);
|
||||
function GenerateBlockAssignments: Int64;
|
||||
// TODO: Blocks is not needed?
|
||||
//property Blocks: TBlocks read FBlocks;
|
||||
function CalcCombinationsWildcardSequence(const ASequenceLength, AStartIndex, AStopIndex: Integer): Int64;
|
||||
property Validation: TIntegerList read FValidation;
|
||||
end;
|
||||
|
||||
|
@ -147,8 +162,6 @@ type
|
|||
|
||||
THotSprings = class(TSolver)
|
||||
private
|
||||
// Keeping the binomial coefficients calculator here so it can be shared for all lines.
|
||||
FBinomialCoefficients: TBinomialCoefficientCache;
|
||||
// TODO: Remove FDebugIndex.
|
||||
FDebugIndex: Integer;
|
||||
public
|
||||
|
@ -206,9 +219,9 @@ begin
|
|||
inherited Destroy;
|
||||
end;
|
||||
|
||||
{ TValidationToDamageAssignments }
|
||||
{ TDamageToValidationAssignments }
|
||||
|
||||
function TValidationToDamageAssignments.CalcValidationSpan(constref ACurrentIndexArray: TIndexArray;
|
||||
function TDamageToValidationAssignments.CalcValidationSpan(constref ACurrentIndexArray: TIndexArray;
|
||||
const ALastDamageIndex, AValidationNumber: Integer): Integer;
|
||||
var
|
||||
spanStart: Integer;
|
||||
|
@ -221,7 +234,7 @@ begin
|
|||
Inc(Result, FDamages[ALastDamageIndex].Start - FDamages[spanStart].Start);
|
||||
end;
|
||||
|
||||
constructor TValidationToDamageAssignments.Create(constref AValidation: TIntegerList; constref AValidationLengths:
|
||||
constructor TDamageToValidationAssignments.Create(constref AValidation: TIntegerList; constref AValidationLengths:
|
||||
TValidationLengths; constref ADamages: TDamages; const AStartIndex, AStopIndex: Integer);
|
||||
begin
|
||||
FValidation := AValidation;
|
||||
|
@ -231,12 +244,12 @@ begin
|
|||
FValidationStopIndex := AStopIndex;
|
||||
end;
|
||||
|
||||
function TValidationToDamageAssignments.GetCardinality: Integer;
|
||||
function TDamageToValidationAssignments.GetCardinality: Integer;
|
||||
begin
|
||||
Result := FDamages.Count;
|
||||
end;
|
||||
|
||||
function TValidationToDamageAssignments.TryGetStartIndexValue(constref ACurrentIndexArray: TIndexArray;
|
||||
function TDamageToValidationAssignments.TryGetStartIndexValue(constref ACurrentIndexArray: TIndexArray;
|
||||
const ACurrentIndex: Integer; out AStartIndexValue: Integer): Boolean;
|
||||
begin
|
||||
Result := True;
|
||||
|
@ -246,7 +259,7 @@ begin
|
|||
AStartIndexValue := FValidationStartIndex;
|
||||
end;
|
||||
|
||||
function TValidationToDamageAssignments.ValidateIndexValue(constref ACurrentIndexArray: TIndexArray;
|
||||
function TDamageToValidationAssignments.ValidateIndexValue(constref ACurrentIndexArray: TIndexArray;
|
||||
const ACurrentIndex: Integer): TIndexValidationResult;
|
||||
var
|
||||
i, prev, firstSkip: Integer;
|
||||
|
@ -296,13 +309,71 @@ begin
|
|||
Result := ivrValid;
|
||||
end;
|
||||
|
||||
{ TAccumulatedCombinationsMultiIndexStrategy }
|
||||
|
||||
function TAccumulatedCombinationsMultiIndexStrategy.UpdateCombinations(const AValidationResult: TIndexValidationResult;
|
||||
constref ACurrentIndexArray: TIndexArray; const ACurrentIndex: Integer): TIndexValidationResult;
|
||||
var
|
||||
combinations: Int64;
|
||||
begin
|
||||
Result := AValidationResult;
|
||||
if Result = ivrValid then
|
||||
begin
|
||||
combinations := CalcCombinations(ACurrentIndexArray, ACurrentIndex);
|
||||
if combinations = 0 then
|
||||
Result := ivrBacktrack
|
||||
else if ACurrentIndex > 0 then
|
||||
FAccumulatedCombinations[ACurrentIndex] := combinations * FAccumulatedCombinations[ACurrentIndex - 1]
|
||||
else begin
|
||||
SetLength(FAccumulatedCombinations, GetCardinality);
|
||||
FAccumulatedCombinations[ACurrentIndex] := combinations;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TAccumulatedCombinationsMultiIndexStrategy.GetCombinations: Int64;
|
||||
begin
|
||||
Result := FAccumulatedCombinations[GetCardinality - 1];
|
||||
end;
|
||||
|
||||
{ TValidationPositionOffsets }
|
||||
|
||||
constructor TValidationPositionOffsets.Create(constref AValidation: TIntegerList; constref APositionInfos:
|
||||
TValidationPositionInfos);
|
||||
function TValidationPositionOffsets.CalcCombinations(constref ACurrentIndexArray: TIndexArray; const ACurrentIndex:
|
||||
Integer): Int64;
|
||||
var
|
||||
space, start, stop: Integer;
|
||||
begin
|
||||
FValidation := AValidation;
|
||||
stop := FPositionInfos[ACurrentIndex].ValidationIndex - 1;
|
||||
if ACurrentIndex > 0 then
|
||||
begin
|
||||
space := ACurrentIndexArray[ACurrentIndex] - ACurrentIndexArray[ACurrentIndex - 1]
|
||||
- FConditionRecord.Validation[FPositionInfos[ACurrentIndex - 1].ValidationIndex] - 2;
|
||||
start := FPositionInfos[ACurrentIndex - 1].ValidationIndex + 1;
|
||||
Result := FConditionRecord.CalcCombinationsWildcardSequence(space, start, stop);
|
||||
end
|
||||
else begin
|
||||
// Handles first calculated offset.
|
||||
space := ACurrentIndexArray[0] - 2;
|
||||
Result := FConditionRecord.CalcCombinationsWildcardSequence(space, FStartIndex, stop);
|
||||
end;
|
||||
|
||||
if (Result > 0) and (ACurrentIndex + 1 = GetCardinality) then
|
||||
begin
|
||||
// Handles last calculated offset.
|
||||
space := FBlockLength - ACurrentIndexArray[ACurrentIndex] - FConditionRecord.Validation[FPositionInfos.Last.ValidationIndex];
|
||||
Result := Result * FConditionRecord.CalcCombinationsWildcardSequence(space, FPositionInfos.Last.ValidationIndex + 1, FStopIndex);
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TValidationPositionOffsets.Create(constref AConditionRecord: TConditionRecord; constref APositionInfos:
|
||||
TValidationPositionInfos; const ABlockLength, AStartIndex, AStopIndex: Integer);
|
||||
begin
|
||||
FConditionRecord := AConditionRecord;
|
||||
FPositionInfos := APositionInfos;
|
||||
FBlockLength := ABlockLength;
|
||||
FStartIndex := AStartIndex;
|
||||
FStopIndex := AStopIndex;
|
||||
inherited Create;
|
||||
end;
|
||||
|
||||
function TValidationPositionOffsets.GetCardinality: Integer;
|
||||
|
@ -317,13 +388,12 @@ var
|
|||
begin
|
||||
info := FPositionInfos[ACurrentIndex];
|
||||
// Calculates start value such that the validation number just includes MinEnd.
|
||||
//AStartIndexValue := info.MinEnd - FValidation[info.ValidationIndex] + 1;
|
||||
AStartIndexValue := info.MinStart;
|
||||
// Adjusts start value to avoid overlap of this validation number with the previous one (the one from previous
|
||||
// position info).
|
||||
if ACurrentIndex > 0 then
|
||||
AStartIndexValue := Max(AStartIndexValue,
|
||||
ACurrentIndexArray[ACurrentIndex - 1] + FValidation[FPositionInfos[ACurrentIndex - 1].ValidationIndex] + 1);
|
||||
ACurrentIndexArray[ACurrentIndex - 1] + FConditionRecord.Validation[FPositionInfos[ACurrentIndex - 1].ValidationIndex] + 1);
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
|
@ -334,6 +404,8 @@ begin
|
|||
Result := ivrValid
|
||||
else
|
||||
Result := ivrBacktrack;
|
||||
|
||||
Result := UpdateCombinations(Result, ACurrentIndexArray, ACurrentIndex);
|
||||
end;
|
||||
|
||||
{ TConditionRecord }
|
||||
|
@ -413,7 +485,7 @@ function TConditionRecord.CalcCombinationsBlock(constref ABlock: TBlock; const A
|
|||
var
|
||||
i, j, k: Integer;
|
||||
indices: TIndexArray;
|
||||
validationToDamageAssignments: TValidationToDamageAssignments;
|
||||
validationToDamageAssignments: TDamageToValidationAssignments;
|
||||
begin
|
||||
{$ifdef debug}
|
||||
Write(' ', ABlock.Pattern, ' ');
|
||||
|
@ -464,7 +536,7 @@ begin
|
|||
Result := 0;
|
||||
|
||||
// Assigns validation numbers to specific damages.
|
||||
validationToDamageAssignments := TValidationToDamageAssignments.Create(FValidation, FValidationLengths, ABlock.Damages,
|
||||
validationToDamageAssignments := TDamageToValidationAssignments.Create(FValidation, FValidationLengths, ABlock.Damages,
|
||||
AStartIndex, AStopIndex);
|
||||
{$ifdef debug}
|
||||
WriteLn(' validation numbers (indices) per damages:');
|
||||
|
@ -551,82 +623,17 @@ begin
|
|||
WriteLn(' offsets');
|
||||
{$endif}
|
||||
Result := 0;
|
||||
validationPositionOffsets := TValidationPositionOffsets.Create(FValidation, positions);
|
||||
validationPositionOffsets := TValidationPositionOffsets.Create(Self, positions, Length(ABlock.Pattern),
|
||||
AStartIndex, AStopIndex);
|
||||
for offsets in validationPositionOffsets do
|
||||
Result := Result
|
||||
+ CalcCombinationsBlockAssignedValidations(Length(ABlock.Pattern), positions, offsets, AStartIndex, AStopIndex);
|
||||
Result := Result + validationPositionOffsets.GetCombinations;
|
||||
validationPositionOffsets.Free;
|
||||
|
||||
positions.Free;
|
||||
end;
|
||||
|
||||
function TConditionRecord.CalcCombinationsBlockAssignedValidations(const ABlockLength: Integer; constref APositionInfos:
|
||||
TValidationPositionInfos; constref AOffsets: TIndexArray; const AStartIndex, AStopIndex: Integer): Int64;
|
||||
var
|
||||
i, space: Integer;
|
||||
constructor TConditionRecord.Create;
|
||||
begin
|
||||
{$ifdef debug}
|
||||
Write(' ');
|
||||
for i in AOffsets do
|
||||
Write(i, ' ');
|
||||
|
||||
Write(' count/space/freedoms: ');
|
||||
{$endif}
|
||||
space := AOffsets[0] - 2;
|
||||
Result := CalcCombinationsWildcardSequence(space, AStartIndex, APositionInfos[0].ValidationIndex - 1);
|
||||
if Result = 0 then begin
|
||||
{$ifdef debug}
|
||||
WriteLn(' result: ', Result);
|
||||
{$endif}
|
||||
Exit;
|
||||
end;
|
||||
|
||||
for i := 0 to APositionInfos.Count - 2 do begin
|
||||
space := AOffsets[i + 1] - AOffsets[i] - FValidation[APositionInfos[i].ValidationIndex] - 2;
|
||||
Result := Result * CalcCombinationsWildcardSequence(space, APositionInfos[i].ValidationIndex + 1, APositionInfos[i + 1].ValidationIndex - 1);
|
||||
if Result = 0 then begin
|
||||
{$ifdef debug}
|
||||
WriteLn(' result: ', Result);
|
||||
{$endif}
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
space := ABlockLength - AOffsets[APositionInfos.Count - 1] - FValidation[APositionInfos.Last.ValidationIndex];
|
||||
Result := Result * CalcCombinationsWildcardSequence(space, APositionInfos.Last.ValidationIndex + 1, AStopIndex);
|
||||
{$ifdef debug}
|
||||
WriteLn(' result: ', Result);
|
||||
{$endif}
|
||||
end;
|
||||
|
||||
function TConditionRecord.CalcCombinationsWildcardSequence(const ASequenceLength, AStartIndex, AStopIndex: Integer):
|
||||
Int64;
|
||||
var
|
||||
count, freedoms: Integer;
|
||||
begin
|
||||
if AStartIndex < AStopIndex + 1 then
|
||||
begin
|
||||
count := AStopIndex + 1 - AStartIndex;
|
||||
freedoms := ASequenceLength - FValidationLengths[AStartIndex, AStopIndex + 1];
|
||||
{$ifdef debug}
|
||||
Write(count, '/', ASequenceLength, '/', freedoms, ' ');
|
||||
{$endif}
|
||||
if freedoms >= 0 then
|
||||
Result := FBinomialCoefficients.Get(count + freedoms, freedoms)
|
||||
else
|
||||
Result := 0;
|
||||
end
|
||||
else begin
|
||||
Result := 1;
|
||||
{$ifdef debug}
|
||||
Write('X ');
|
||||
{$endif}
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TConditionRecord.Create(constref ABinomialCoefficients: TBinomialCoefficientCache);
|
||||
begin
|
||||
FBinomialCoefficients := ABinomialCoefficients;
|
||||
|
||||
FBlocks := TBlocks.Create;
|
||||
FValidation := TIntegerList.Create;
|
||||
end;
|
||||
|
@ -710,17 +717,40 @@ begin
|
|||
WriteLn(' missed: ', misses, '/', count);
|
||||
end;
|
||||
|
||||
function TConditionRecord.CalcCombinationsWildcardSequence(const ASequenceLength, AStartIndex, AStopIndex: Integer):
|
||||
Int64;
|
||||
var
|
||||
count, freedoms: Integer;
|
||||
begin
|
||||
if AStartIndex < AStopIndex + 1 then
|
||||
begin
|
||||
count := AStopIndex + 1 - AStartIndex;
|
||||
freedoms := ASequenceLength - FValidationLengths[AStartIndex, AStopIndex + 1];
|
||||
{$ifdef debug}
|
||||
Write(count, '/', ASequenceLength, '/', freedoms, ' ');
|
||||
{$endif}
|
||||
if freedoms >= 0 then
|
||||
Result := BinomialCoefficients.Get(count + freedoms, freedoms)
|
||||
else
|
||||
Result := 0;
|
||||
end
|
||||
else begin
|
||||
Result := 1;
|
||||
{$ifdef debug}
|
||||
Write('X ');
|
||||
{$endif}
|
||||
end;
|
||||
end;
|
||||
|
||||
{ THotSprings }
|
||||
|
||||
constructor THotSprings.Create;
|
||||
begin
|
||||
FDebugIndex := 0;
|
||||
FBinomialCoefficients := TBinomialCoefficientCache.Create;
|
||||
end;
|
||||
|
||||
destructor THotSprings.Destroy;
|
||||
begin
|
||||
FBinomialCoefficients.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
|
@ -736,8 +766,8 @@ begin
|
|||
WriteLn;
|
||||
{$endif}
|
||||
|
||||
conditionRecord1 := TConditionRecord.Create(FBinomialCoefficients);
|
||||
conditionRecord2 := TConditionRecord.Create(FBinomialCoefficients);
|
||||
conditionRecord1 := TConditionRecord.Create;
|
||||
conditionRecord2 := TConditionRecord.Create;
|
||||
|
||||
mainSplit := ALine.Split([' ']);
|
||||
|
||||
|
|
Loading…
Reference in New Issue