Skip to content

Commit 7020386

Browse files
committed
Add levenshtein
1 parent e97d35d commit 7020386

File tree

6 files changed

+197
-108
lines changed

6 files changed

+197
-108
lines changed

levenshtein/csharp/code.cs

-81
This file was deleted.

levenshtein/csharp/in-process/code.cs

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
using System.Runtime.CompilerServices;
2+
3+
var runMs = int.Parse(args[0]);
4+
var warmupMs = int.Parse(args[1]);
5+
var inputPath = args[2];
6+
7+
var content = File.ReadAllLines(inputPath);
8+
9+
Benchmark<List<int>>.Run(() => Levenshtein(content), warmupMs);
10+
11+
var result = Benchmark<List<int>>.Run(() => Levenshtein(content), runMs);
12+
13+
var summedResult = new BenchmarkResult<int>(
14+
result!.MeanMs,
15+
result.StdDevMs,
16+
result.MinMs,
17+
result.MaxMs,
18+
result.Runs,
19+
result.Result.Sum());
20+
21+
Console.WriteLine(summedResult);
22+
23+
return;
24+
25+
static List<int> Levenshtein(string[] content)
26+
{
27+
var distances = new List<int>();
28+
29+
for (var i = 0; i < content.Length; i++)
30+
{
31+
for (var j = i + 1; j < content.Length; j++)
32+
{
33+
distances.Add(LevenshteinDistance(content[i], content[j]));
34+
}
35+
}
36+
37+
return distances;
38+
}
39+
40+
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
41+
static int LevenshteinDistance(ReadOnlySpan<char> str1, ReadOnlySpan<char> str2)
42+
{
43+
// Early termination checks
44+
if (str1.SequenceEqual(str2))
45+
{
46+
return 0;
47+
}
48+
49+
if (str1.IsEmpty)
50+
{
51+
return str2.Length;
52+
}
53+
54+
if (str2.IsEmpty)
55+
{
56+
return str1.Length;
57+
}
58+
59+
// Ensure str1 is the shorter string
60+
if (str1.Length > str2.Length)
61+
{
62+
var strtemp = str2;
63+
str2 = str1;
64+
str1 = strtemp;
65+
}
66+
67+
// Create two rows, previous and current
68+
Span<int> prev = stackalloc int[str1.Length + 1];
69+
Span<int> curr = stackalloc int[str1.Length + 1];
70+
71+
// initialize the previous row
72+
for (var i = 0; i <= str1.Length; i++)
73+
{
74+
prev[i] = i;
75+
}
76+
77+
// Iterate and compute distance
78+
for (var i = 1; i <= str2.Length; i++)
79+
{
80+
curr[0] = i;
81+
for (var j = 1; j <= str1.Length; j++)
82+
{
83+
var cost = (str1[j - 1] == str2[i - 1]) ? 0 : 1;
84+
curr[j] = Math.Min(
85+
prev[j] + 1, // Deletion
86+
Math.Min(curr[j - 1] + 1, // Insertion
87+
prev[j - 1] + cost) // Substitution
88+
);
89+
}
90+
91+
// Swap spans
92+
var temp = prev;
93+
prev = curr;
94+
curr = temp;
95+
}
96+
97+
// Return final distance, stored in prev[m]
98+
return prev[str1.Length];
99+
}
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net9.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<Compile Include="..\..\..\lib\csharp\benchmark.cs">
12+
<Link>benchmark.cs</Link>
13+
</Compile>
14+
</ItemGroup>
15+
16+
</Project>

levenshtein/csharp/legacy/code.cs

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
using System.Runtime.CompilerServices;
2+
3+
int min_distance = -1;
4+
int times = 0;
5+
for (int i = 0; i < args.Length; i++)
6+
{
7+
for (int j = 0; j < args.Length; j++)
8+
{
9+
if (i != j)
10+
{
11+
int distance = levenshtein(args[i], args[j]);
12+
if (min_distance == -1 || min_distance > distance)
13+
{
14+
min_distance = distance;
15+
}
16+
times++;
17+
}
18+
}
19+
}
20+
Console.WriteLine($"times: {times}");
21+
Console.WriteLine($"min_distance: {min_distance}");
22+
23+
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
24+
static int levenshtein(ReadOnlySpan<char> str1, ReadOnlySpan<char> str2)
25+
{
26+
// Early termination checks
27+
if (str1.SequenceEqual(str2))
28+
{
29+
return 0;
30+
}
31+
if (str1.IsEmpty)
32+
{
33+
return str2.Length;
34+
}
35+
if (str2.IsEmpty)
36+
{
37+
return str1.Length;
38+
}
39+
40+
// Ensure str1 is the shorter string
41+
if (str1.Length > str2.Length)
42+
{
43+
var strtemp = str2;
44+
str2 = str1;
45+
str1 = strtemp;
46+
}
47+
48+
// Create two rows, previous and current
49+
Span<int> prev = stackalloc int[str1.Length + 1];
50+
Span<int> curr = stackalloc int[str1.Length + 1];
51+
52+
// initialize the previous row
53+
for (int i = 0; i <= str1.Length; i++)
54+
{
55+
prev[i] = i;
56+
}
57+
58+
// Iterate and compute distance
59+
for (int i = 1; i <= str2.Length; i++)
60+
{
61+
curr[0] = i;
62+
for (int j = 1; j <= str1.Length; j++)
63+
{
64+
int cost = (str1[j - 1] == str2[i - 1]) ? 0 : 1;
65+
curr[j] = Math.Min(
66+
prev[j] + 1, // Deletion
67+
Math.Min(curr[j - 1] + 1, // Insertion
68+
prev[j - 1] + cost) // Substitution
69+
);
70+
}
71+
72+
// Swap spans
73+
var temp = prev;
74+
prev = curr;
75+
curr = temp;
76+
}
77+
78+
// Return final distance, stored in prev[m]
79+
return prev[str1.Length];
80+
}
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
@@ -7,10 +7,4 @@
77
<Nullable>enable</Nullable>
88
</PropertyGroup>
99

10-
<ItemGroup>
11-
<Compile Include="..\..\lib\csharp\Benchmark.cs">
12-
<Link>Benchmark.cs</Link>
13-
</Compile>
14-
</ItemGroup>
15-
16-
</Project>
10+
</Project>

levenshtein/csharp/run.cs

-19
This file was deleted.

0 commit comments

Comments
 (0)