Skip to content

Add lambda score for Ai-Mj #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jul 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Icfpc2023/Geometry.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ type PointD =
| PointD of double * double
member this.X = match this with PointD(x, _) -> x
member this.Y = match this with PointD(_, y) -> y
member this.SquaredDistanceTo(p: PointD): double =
let (PointD(x1, y1)) = this
let (PointD(x2, y2)) = p
(x1 - x2) ** 2.0 + (y1 - y2) ** 2.0

member this.DistanceTo(p: PointD): double =
sqrt <| this.SquaredDistanceTo p

[<Struct>]
type Stadium =
Expand Down
1 change: 1 addition & 0 deletions Icfpc2023/Icfpc2023.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<Compile Include="DummySolver.fs" />
<Compile Include="JsonDefs.fs" />
<Compile Include="HttpApi.fs" />
<Compile Include="LambdaScore.fs" />
<Compile Include="Program.fs" />
</ItemGroup>

Expand Down
99 changes: 99 additions & 0 deletions Icfpc2023/LambdaScore.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
module Icfpc2023.LambdaScore

open System
open System.Linq

let OVERLAP_DISTANCE = 5.0
let MUSICAL_MIN_DISTANCE = 10.0

let distance_point(A: PointD, M) =
A.DistanceTo(M)

// square distance between A and M
let distance2_point(A: PointD, M) =
A.SquaredDistanceTo(M)

// compute parameters of line a*x + b*y + c = 0 which pass through A and M points
let line_parameter(A: PointD, M: PointD) =
let a = A.Y - M.Y
let b = M.X - A.X
let c = -a*M.X - b*M.Y
a, b, c

// compute distance between line (a*x + b*y + c = 0) and point
// base points (B1, B2) are using to determine if point is between them, otherwise we can set distance to infinity (1000 is enough)
let distance_point_line(line, point, B1: PointD, B2: PointD) =
let a, b, c = line
let (PointD(x0, y0)) = point
let x_line = (b*( b*x0 - a*y0) - a*c) / (a*a + b*b)
let y_line = (a*(-b*x0 + a*y0) - b*c) / (a*a + b*b)
if B1.X > x_line && B2.X > x_line then
1000.0
else if B1.X < x_line && B2.X < x_line then
1000.0
else if B1.Y > y_line && B2.Y > y_line then
1000.0
else if B1.Y < y_line && B2.Y < y_line then
1000.0
else distance_point(PointD(x0, y0), PointD(x_line, y_line))

// lambda factor (jt-th Musician between i-th Attendee and j-th Musician)
// when overlapping is, return 0
// when no overlapping, return 1
// the idea is to replace step function with continuous function with some parameter for easier gradient-based optimization algorithms
// lambda changes behavior of gate
let lambda_factor(labda, Ai, Mj: PointD, Mjt: PointD) =
let line_Ai_Mj = line_parameter(Ai, Mj) // (a, b, c) typle
let point_Mjt = (Mjt.X, Mjt.Y) // (x0, y0) typle
2. / Math.PI * atan(labda*(distance_point_line(line_Ai_Mj, Mjt, Ai, Mj) - OVERLAP_DISTANCE)) + 1.0

// lambda score between A_i and M_j
//
// A - Attendee, i-th
// M - Musician, j-th
// T - taste matrix
// lambda - parameter; exact solution when -> infty
let lambda_score_AiMj(A: PointD[], M: PointD[], i, j, T: double[,], labda) =
let mutable res = T[i,j] // distance2_point(A[i], M[j])
for jt in Enumerable.Range(0, M.Length) do
if jt <> j then
res <- res * lambda_factor(labda, A[i], M[j], M[jt])
res

// lambda score between M_i and M_j
//
// M - Musician, i-th
// M - Musician, j-th
// lambda - parameter; exact solution when -> infty
let lambda_score_MiMj(M: PointD[], i, j, labda) =
(2. / Math.PI * atan(labda * (distance_point(M[i], M[j]) - MUSICAL_MIN_DISTANCE)) + 1.0) * 100.0

let DoTest() =
let p1 = PointD(2,3)
let p2 = PointD(2,4)
let a,b,c = line_parameter(p1, p2)
printfn "%A" (a,b,c)
printfn "%A" (a*p1.X + b*p1.Y + c)
printfn "%A" (a*p2.X + b*p2.Y + c)

let p1 = PointD(3,2)
let p2 = PointD(4,2)
let a,b,c = line_parameter(p1, p2)
printfn "%A" (a,b,c)
printfn "%A" (a*p1.X + b*p1.Y + c)
printfn "%A" (a*p2.X + b*p2.Y + c)

let p1 = PointD(3,3)
let p2 = PointD(4,4)
let a,b,c = line_parameter(p1, p2)
printfn "%A" (a,b,c)
printfn "%A" (a*p1.X + b*p1.Y + c)
printfn "%A" (a*p2.X + b*p2.Y + c)

let p1 = PointD(3,3)
let p2 = PointD(6,0)
let a,b,c = line_parameter(p1, p2)
printfn "%A" (a,b,c)
printfn "%A" (a*p1.X + b*p1.Y + c)
printfn "%A" (a*p2.X + b*p2.Y + c)

3 changes: 3 additions & 0 deletions Icfpc2023/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ let main(args: string[]): int =
let submission = { ProblemId = problemNumber; Contents = File.ReadAllText(solution) }
runSynchronouslyV <| Upload(submission, token)

| [| "lambdaScore" |] ->
LambdaScore.DoTest()

| _ -> printfn "Command unrecognized."

0
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ Calculate score for solution 1 on problem 1:
$ dotnet run --project Icfpc2023 -- score 1
```

#### Oddities
Lambda score showcase (I dunno, see [PR #4](https://github.com/codingteam/icfpc-2023/pull/4/) for details):
```console
$ dotnet run --project Icfpc2023 -- lambdaScore
```

#### Legacy
Download first 3 problems:

Expand Down
106 changes: 106 additions & 0 deletions lambda_score.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#!/usr/bin/env python3

import math

OVERLAP_DISTANCE = 5

# distance between A and M
def distance_point(A, M):
return math.sqrt((A.x - M.x)**2 + (A.y - M.y)**2)

# square distance between A and M
def distance2_point(A, M):
return (A.x - M.x)**2 + (A.y - M.y)**2

# compute parameters of line a*x + b*y + c = 0 which pass through A and M points
def line_parameter(A, M):
a = A.y - M.y
b = M.x - A.x
c = -a*M.x - b*M.y
return (a, b, c)

# compute distance between line (a*x + b*y + c = 0) and point
# base points (B1, B2) are using to determine if point is between them, otherwise we can set distance to infinity (1000 is enough)
def distance_point_line(line, point, B1, B2):
a, b, c = line
x0, y0 = point
x_line = (b*( b*x0 - a*y0) - a*c) / (a*a + b*b)
y_line = (a*(-b*x0 + a*y0) - b*c) / (a*a + b*b)
if B1.x > x_line and B2.x > x_line:
return 1000.0
if B1.x < x_line and B2.x < x_line:
return 1000.0
if B1.y > y_line and B2.y > y_line:
return 1000.0
if B1.y < y_line and B2.y < y_line:
return 1000.0
return distance_point(Point(x0, y0), Point(x_line, y_line))

# lambda factor (jt-th Musician between i-th Attendee and j-th Musician)
# when overlapping is, return 0
# when no overlapping, return 1
# the idea is to replace step function with continuous function with some parameter for easier gradient-based optimization algorithms
# lambda changes behavior of gate
def lambda_factor(labda, Ai, Mj, Mjt):
line_Ai_Mj = line_parameter(Ai, Mj) # (a, b, c) typle
point_Mjt = (Mjt.x, Mjt.y) # (x0, y0) typle
return 2. / math.pi * math.atan(labda*(distance_point_line(line_Ai_Mj, Mjt) - OVERLAP_DISTANCE)) + 1

# lambda score between A_i and M_j
#
# A - Attendee, i-th
# M - Musician, j-th
# T - taste matrix
# lambda - parameter; exact solution when -> infty
def lambda_score_AiMj(A, M, i, j, T, labda):
res = T[i,j] // distance2_point(A[i], M[j])
for jt in range(0, len(M)):
if jt != j:
res *= lambda_factor(labda, A[i], M[j], M[jt])
return res

# lambda score between M_i and M_j
#
# M - Musician, i-th
# M - Musician, j-th
# lambda - parameter; exact solution when -> infty
def lambda_score_MiMj(M, i, j, labda):
return (2. / math.pi * math.atan(labda * (distance_point(M[i], M[j]) - MUSICAL_MIN_DISTANCE)) + 1) * 100

# to test
class Point:
def __init__(self):
self.x = 0
self.y = 0
def __init__(self, x, y):
self.x = x
self.y = y

p1 = Point(2,3)
p2 = Point(2,4)
a,b,c = line_parameter(p1, p2)
print(a,b,c)
print(a*p1.x + b*p1.y + c)
print(a*p2.x + b*p2.y + c)

p1 = Point(3,2)
p2 = Point(4,2)
a,b,c = line_parameter(p1, p2)
print(a,b,c)
print(a*p1.x + b*p1.y + c)
print(a*p2.x + b*p2.y + c)

p1 = Point(3,3)
p2 = Point(4,4)
a,b,c = line_parameter(p1, p2)
print(a,b,c)
print(a*p1.x + b*p1.y + c)
print(a*p2.x + b*p2.y + c)

p1 = Point(3,3)
p2 = Point(6,0)
a,b,c = line_parameter(p1, p2)
print(a,b,c)
print(a*p1.x + b*p1.y + c)
print(a*p2.x + b*p2.y + c)