Skip to content

Commit

Permalink
loopblock important calculations, loops visualization in tests improv…
Browse files Browse the repository at this point in the history
…ed (loop length shown)
  • Loading branch information
pavel-zhur committed Jul 19, 2024
1 parent 7afedde commit 47b7758
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,7 @@ public void Random100X100WithChordTypes()
RootDelta = (byte)d,
FromType = chordType,
ToType = chordType = GetRandomChordType(),
}).ToArray();
}).Where(m => m.FromType != m.ToType || m.RootDelta != 0).ToArray();

var firstRoot = (byte)Random.Shared.Next(0, 12);
var loops = indexExtractor.FindSimpleLoops(sequence, firstRoot, out _);
Expand Down Expand Up @@ -746,9 +746,32 @@ private void TraceAndTest(

var roots = indexExtractor.CreateRoots(sequence, firstRoot);

Assert.All(loops, l => Assert.True(l.LoopLength > 1));

Assert.All(loops, l => Assert.Equal(
l.Successions == Math.Round(l.Successions),
l.Occurrences == Math.Round(l.Occurrences)));

Assert.All(loops, l => Assert.True(l.Occurrences >= 1));
Assert.All(loops, l => Assert.True(l.Successions >= 0));

Assert.All(loops, l => Assert.False(
l.Occurrences == Math.Round(l.Occurrences)
&& l.EachChordCoveredTimes == Math.Round(l.EachChordCoveredTimes)));

Assert.All(loops, l => Assert.True(l.EachChordCoveredTimes > 1 + float.Epsilon));

Assert.All(loops, l => Assert.Equal(
l.EachChordCoveredTimes == Math.Round(l.EachChordCoveredTimes),
roots[l.StartIndex + l.LoopLength - 1] == roots[l.EndIndex + 1] && sequence.Span[l.StartIndex + l.LoopLength - 1].FromType == sequence.Span[l.EndIndex].ToType));

Assert.All(loops, l => Assert.Equal(
l.Successions == Math.Round(l.Successions),
roots[l.StartIndex] == roots[l.EndIndex + 1] && sequence.Span[l.StartIndex].FromType == sequence.Span[l.EndIndex].ToType));

string CreateRootsTrace(IBlock block) => CreateRootsTraceByIndices(block.StartIndex, block.EndIndex, out _);

string CreateRootsTraceByIndices(int coveredByStartIndex, int coveredByEndIndex, out List<(int startPosition, int endPosition)> positions, bool typesToo = true)
string CreateRootsTraceByIndices(int coveredByStartIndex, int coveredByEndIndex, out List<int> positions, bool typesToo = true)
{
var builder = new StringBuilder();
builder.Append(roots[coveredByStartIndex]);
Expand All @@ -759,7 +782,7 @@ string CreateRootsTraceByIndices(int coveredByStartIndex, int coveredByEndIndex,

positions =
[
(0, builder.Length - 1),
0,
];

for (var i = coveredByStartIndex; i <= coveredByEndIndex; i++)
Expand All @@ -773,7 +796,7 @@ string CreateRootsTraceByIndices(int coveredByStartIndex, int coveredByEndIndex,
builder.Append(sequence.Span[i].ToType.ChordTypeToString());
}

positions.Add((startPosition, builder.Length - 1));
positions.Add(startPosition);
}

return builder.ToString();
Expand All @@ -790,9 +813,29 @@ string CreateRootsTraceByIndices(int coveredByStartIndex, int coveredByEndIndex,
var rootsTrace = CreateRootsTraceByIndices(0, sequence.Length - 1, out var positions, false);

var lines = all
.Select((x, i) => string.Join(string.Empty,
Enumerable.Range(0, rootsTrace.Length).Select(j => positions[x.StartIndex].startPosition <= j && positions[x.EndIndex + 1].endPosition >= j ? '-' : ' '))
+ $" {all[i].GetType().Name}")
.Select((block, i) =>
{
var startPosition = positions[block.StartIndex];
var endPosition = positions[block.EndIndex + 1];
var specialPositions = block is LoopBlock loop
? Enumerable.Range(0, block.BlockLength / loop.LoopLength + 1)
.Select(x => x * loop.LoopLength + block.StartIndex)
.Select(x => positions[x])
: Enumerable.Empty<int>();

return string.Join(
string.Empty,
Enumerable
.Range(0, rootsTrace.Length)
.Select(j =>
startPosition <= j &&
endPosition >= j
? specialPositions.Contains(j)
? '|'
: '-'
: ' '))
+ $" {all[i].GetType().Name}";
})
.ToList();

logger.LogInformation(string.Join(Environment.NewLine, string.Empty.Once()
Expand Down
20 changes: 20 additions & 0 deletions HarmonyDB.Index/HarmonyDB.Index.Analysis/Models/Index/LoopBlock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,24 @@ public record LoopBlock : ILoopBlock
public required int EndIndex { get; init; }

public int BlockLength => EndIndex - StartIndex + 1;

/// <summary>
/// Is a whole number of and only if edge chords are the same. Min = 1.
/// Greater than 1 if at least one movement repeats twice.
/// Equals 1 if all chords repeat once except the edge ones.
/// </summary>
public float Occurrences => (float)BlockLength / LoopLength;

/// <summary>
/// Is a whole number of and only if edge chords are the same. Min = 0.
/// Greater than 0 if at least one movement repeats twice.
/// Equals 0 if all chords repeat once except the edge ones.
/// </summary>
public float Successions => (float)BlockLength / LoopLength - 1;

/// <summary>
/// Greater than 1. Is a whole if all chords repeat exactly the same number of times, like A B C D A B C D A B C D.
/// Might be a convenient indicator of significance (if value >= 2).
/// </summary>
public float EachChordCoveredTimes => (float)(BlockLength + 1) / LoopLength;
}
Original file line number Diff line number Diff line change
Expand Up @@ -298,11 +298,10 @@ public List<StructureLink> FindStructureLinks(string externalId, CompactChordsPr
{
var key = (loop.Normalized, loop.NormalizationRoot);
var counters = loopResults.GetValueOrDefault(key);
var length = loop.EndIndex - loop.StartIndex + 1;
loopResults[key] = ((float occurrences, float successions, short length))(
counters.occurrences + (float)length / loop.LoopLength,
counters.successions + (float)length / loop.LoopLength - 1,
counters.length + length);
counters.occurrences + loop.Occurrences,
counters.successions + loop.Successions,
counters.length + loop.BlockLength);
}
}

Expand Down

0 comments on commit 47b7758

Please sign in to comment.