Jdi na navigaci předmětu

3. Porovnání (Kulečník)

Porovnání jednotlivých řešení.

using CSV, DataFrames
"""

Pomocná hodnotící funkce přidělující body ve sloupci `score` pod pořadí ve sloupci `column` (seřazeném).

"""
function record_rank!(data_frame::DataFrame, column::Symbol)
    rank = 1
    value = first(data_frame[!, column])

    for row in eachrow(data_frame)
        if !ismissing(row[column]) && row[column] != value
            value = row[column]
            rank += 1
        end

        row[:score] += rank
    end
end
record_rank!

Načtení dat a přidání "skórovacího" sloupce.

df = CSV.read("results03.csv", DataFrame)
df[!, "score"] .= 0
describe(df)
7×7 DataFrame
Rowvariablemeanminmedianmaxnmissingeltype
SymbolUnion…AnyUnion…AnyInt64Type
1nicknameAheroninUwyss0String15
2simulate_time6.97308e83.87019e86.12738e81.81023e920Union{Missing, Float64}
3simulate_mem6.06668e82579260325.54537e8118348937620Union{Missing, Int64}
4check_x20.5632-160.89668.640868.640820Union{Missing, Float64}
5check_y-217.579-272.722-272.722176.89820Union{Missing, Float64}
6error(Not found)ErrorException (simulation)13Union{Missing, String31}
7score0.000.000Int64

Pozor! Tento benchmark nebyl úplně přímočarý na provedení. Řada implementací zdá se zvláštně selhává :-). Do sloupce error jsem zaznamenal důvod:

  • Not found: úkol nebyl odevzdán,
  • simulation: výjimka při pokusu o spuštění simulace (popis situace viz níže),
  • Table constructor: výjimka při pokusu o vytvoření kulečníku.
show(df[!,[:nickname, :error]], allrows=true)
33×2 DataFrame
 Row  nickname   error                        String15   String31?                   
─────┼────────────────────────────────────────
   1 │ Kalvotom   missing                     
   2 │ Tiharis    missing                     
   3 │ Asuras     missing                     
   4 │ Khoviar    missing                     
   5 │ Offyn      (Not found)
   6 │ Avesior    (Not found)
   7 │ Elleas     missing                     
   8 │ Apan       missing                     
   9 │ Rhuqihr    missing                     
  10 │ Uwyss      ErrorException (simulation)
  11 │ Uhunyll    ErrorException (simulation)
  12 │ Kharnas    (Not found)
  13 │ Ahith      ErrorException (simulation)
  14 │ Korass     ErrorException (simulation)
  15 │ Isigoris   missing                     
  16 │ Gokelis    (Not found)
  17 │ Ozatosh    ErrorException (simulation)
  18 │ Emitrix    (Not found)
  19 │ Isim       (Not found)
  20 │ Ophuqiohn  ErrorException (simulation)
  21 │ Terias     (Not found)
  22 │ Izohr      (Not found)
  23 │ Uphanneas  (Not found)
  24 │ Awyn       missing                     
  25 │ Tomorith   missing                     
  26 │ Ossaem     ErrorException (simulation)
  27 │ Unnemal    missing                     
  28 │ Enyll      (Not found)
  29 │ Aheronin   ErrorException (simulation)
  30 │ Thodelis   missing                     
  31 │ Khukalis   missing                     
  32 │ Sumorith   (Not found)
  33 │ Eluhion    ErrorException (simulation)

Testovací kulečník

Testovací kulečník je složen ze čtyř segmentů a čtyř oblouků. K vykreslení použiji svoji verzi kódu.

include("kalvotom/src/billiard.jl")
using .Billiard

Definice kulečníku.

table = Table([
    Segment([-200., 100.], [-100., 200.]),
    Segment([100., 200.], [200., 100.]),
    Segment([200., -100.], [100., -200.]),
    Segment([-100., -200.], [-200., -100.]),
    Arc([200., 0.], 100., -pi/2, pi/2),
    Arc([0., -200.], 100., pi, 2pi),
    Arc([-200., 0.], 100., pi/2, 3pi/2),
    Arc([0., 200.], 100., 0., pi)
  ])
Billiard table with 8 obstacles.

Benchmark používá následující počáteční podmínky a výpočet 100 000 odrazů. Zde pro jednoduchost zobrazím jen 100.

path = zeros(4, 100)
path[:, 1] = [100, 100, 0.5, -0.33]
simulate!(table, path)

A konečně výsledný obrázek.

draw_path(table, path)

Rychlost

sort!(df, :simulate_time)
record_rank!(df, :simulate_time)
show(df[!,[:nickname, :simulate_time, :score]], allrows=true)
33×3 DataFrame
 Row  nickname   simulate_time    score  String15   Float64?         Int64 
─────┼───────────────────────────────────
   1 │ Isigoris         3.87019e8      1
   2 │ Apan             4.54388e8      2
   3 │ Tomorith         4.63095e8      3
   4 │ Khukalis         5.38113e8      4
   5 │ Unnemal          5.84782e8      5
   6 │ Tiharis          5.96013e8      6
   7 │ Asuras           6.12738e8      7
   8 │ Awyn             6.30099e8      8
   9 │ Khoviar          6.85689e8      9
  10 │ Kalvotom         6.9666e8      10
  11 │ Elleas           7.26566e8     11
  12 │ Thodelis         8.79622e8     12
  13 │ Rhuqihr          1.81023e9     13
  14 │ Offyn      missing             13
  15 │ Avesior    missing             13
  16 │ Uwyss      missing             13
  17 │ Uhunyll    missing             13
  18 │ Kharnas    missing             13
  19 │ Ahith      missing             13
  20 │ Korass     missing             13
  21 │ Gokelis    missing             13
  22 │ Ozatosh    missing             13
  23 │ Emitrix    missing             13
  24 │ Isim       missing             13
  25 │ Ophuqiohn  missing             13
  26 │ Terias     missing             13
  27 │ Izohr      missing             13
  28 │ Uphanneas  missing             13
  29 │ Ossaem     missing             13
  30 │ Enyll      missing             13
  31 │ Aheronin   missing             13
  32 │ Sumorith   missing             13
  33 │ Eluhion    missing             13

Paměť

sort!(df, :simulate_mem)
record_rank!(df, :simulate_mem)
show(df[!,[:nickname, :simulate_mem, :score]], allrows=true)
33×3 DataFrame
 Row  nickname   simulate_mem  score  String15   Int64?        Int64 
─────┼────────────────────────────────
   1 │ Isigoris      257926032      2
   2 │ Tomorith      462965568      5
   3 │ Apan          470394400      5
   4 │ Awyn          526488288     12
   5 │ Unnemal       530748336     10
   6 │ Asuras        546395616     13
   7 │ Tiharis       554537296     13
   8 │ Khoviar       586101504     17
   9 │ Khukalis      629331824     13
  10 │ Thodelis      664949104     22
  11 │ Kalvotom      734859552     21
  12 │ Elleas        738493744     23
  13 │ Rhuqihr      1183489376     26
  14 │ Offyn           missing     26
  15 │ Avesior         missing     26
  16 │ Uwyss           missing     26
  17 │ Uhunyll         missing     26
  18 │ Kharnas         missing     26
  19 │ Ahith           missing     26
  20 │ Korass          missing     26
  21 │ Gokelis         missing     26
  22 │ Ozatosh         missing     26
  23 │ Emitrix         missing     26
  24 │ Isim            missing     26
  25 │ Ophuqiohn       missing     26
  26 │ Terias          missing     26
  27 │ Izohr           missing     26
  28 │ Uphanneas       missing     26
  29 │ Ossaem          missing     26
  30 │ Enyll           missing     26
  31 │ Aheronin        missing     26
  32 │ Sumorith        missing     26
  33 │ Eluhion         missing     26

Poloha po 10 odrazech

Tento kulečník se také bude chovat chaoticky, takže po uvedených 100 000 odrazech bude u různých výpočtů vlivem i nepatrných zaokrouhlovacích chyb dosaženo velmi rozdílných výsledků.

Podíváme se proto pouze na 10 odrazů. I tak se výsledky přirozeně liší, ale je vidět, že hypotetická správná hodnota je někde kolem bodu [68,272][68, -272]. Z hodnot, které jsou blízko této hodnotě napočteme průměr a budeme měřit pořadí podle vzdálenosti od tohoto bodu.

show(df[!,[:nickname, :check_x, :check_y, :score]], allrows=true)
33×4 DataFrame
 Row  nickname   check_x       check_y      score  String15   Float64?      Float64?     Int64 
─────┼─────────────────────────────────────────────
   1 │ Isigoris        68.6408     -272.722      2
   2 │ Tomorith        68.6408     -272.722      5
   3 │ Apan            68.6408     -272.722      5
   4 │ Awyn          -160.896      -139.104     12
   5 │ Unnemal         68.6408     -272.722     10
   6 │ Asuras          68.6408     -272.722     13
   7 │ Tiharis        -97.295       176.898     13
   8 │ Khoviar         68.6408     -272.722     17
   9 │ Khukalis        68.6408     -272.722     13
  10 │ Thodelis      -160.896      -139.104     22
  11 │ Kalvotom        68.6408     -272.722     21
  12 │ Elleas          68.6408     -272.722     23
  13 │ Rhuqihr         68.6408     -272.722     26
  14 │ Offyn      missing       missing         26
  15 │ Avesior    missing       missing         26
  16 │ Uwyss      missing       missing         26
  17 │ Uhunyll    missing       missing         26
  18 │ Kharnas    missing       missing         26
  19 │ Ahith      missing       missing         26
  20 │ Korass     missing       missing         26
  21 │ Gokelis    missing       missing         26
  22 │ Ozatosh    missing       missing         26
  23 │ Emitrix    missing       missing         26
  24 │ Isim       missing       missing         26
  25 │ Ophuqiohn  missing       missing         26
  26 │ Terias     missing       missing         26
  27 │ Izohr      missing       missing         26
  28 │ Uphanneas  missing       missing         26
  29 │ Ossaem     missing       missing         26
  30 │ Enyll      missing       missing         26
  31 │ Aheronin   missing       missing         26
  32 │ Sumorith   missing       missing         26
  33 │ Eluhion    missing       missing         26
using Statistics
mean_x = mean(filter(x -> floor(Int64, x) == 68, collect(skipmissing(df.check_x))))
mean_y = mean(filter(y -> ceil(Int64, y) == -272, collect(skipmissing(df.check_y))))
(mean_x, mean_y)
(68.64077846426251, -272.7216854302761)
df[!, :distance] .= Inf
for idx in 1:nrow(df)
    if ismissing(df[idx, :check_x])
        continue
    end
    df[idx, :distance] = sqrt((df[idx, :check_x] - mean_x)^2 + (df[idx, :check_y] - mean_y)^2)
end
sort!(df, :distance)
record_rank!(df, :distance)
show(df[!,[:nickname, :distance, :score]], allrows=true)
33×3 DataFrame
 Row  nickname   distance       score  String15   Float64        Int64 
─────┼─────────────────────────────────
   1 │ Tomorith     5.74354e-10      6
   2 │ Khoviar      1.31451e-9      19
   3 │ Kalvotom     1.58204e-9      24
   4 │ Apan         1.61874e-9       9
   5 │ Rhuqihr      1.61997e-9      31
   6 │ Isigoris     1.86925e-9       8
   7 │ Unnemal      1.86925e-9      16
   8 │ Asuras       1.98222e-9      20
   9 │ Elleas       2.12754e-9      31
  10 │ Khukalis     1.19288e-8      22
  11 │ Thodelis   265.595           32
  12 │ Awyn       265.595           23
  13 │ Tiharis    479.263           25
  14 │ Offyn      Inf               39
  15 │ Avesior    Inf               39
  16 │ Uwyss      Inf               39
  17 │ Uhunyll    Inf               39
  18 │ Kharnas    Inf               39
  19 │ Ahith      Inf               39
  20 │ Korass     Inf               39
  21 │ Gokelis    Inf               39
  22 │ Ozatosh    Inf               39
  23 │ Emitrix    Inf               39
  24 │ Isim       Inf               39
  25 │ Ophuqiohn  Inf               39
  26 │ Terias     Inf               39
  27 │ Izohr      Inf               39
  28 │ Uphanneas  Inf               39
  29 │ Ossaem     Inf               39
  30 │ Enyll      Inf               39
  31 │ Aheronin   Inf               39
  32 │ Sumorith   Inf               39
  33 │ Eluhion    Inf               39

Závěrečná tabulka

sort!(df, :score)
show(df[!, [:nickname, :score]], allrows=true)
33×2 DataFrame
 Row  nickname   score  String15   Int64 
─────┼──────────────────
   1 │ Tomorith       6
   2 │ Isigoris       8
   3 │ Apan           9
   4 │ Unnemal       16
   5 │ Khoviar       19
   6 │ Asuras        20
   7 │ Khukalis      22
   8 │ Awyn          23
   9 │ Kalvotom      24
  10 │ Tiharis       25
  11 │ Rhuqihr       31
  12 │ Elleas        31
  13 │ Thodelis      32
  14 │ Offyn         39
  15 │ Avesior       39
  16 │ Uwyss         39
  17 │ Uhunyll       39
  18 │ Kharnas       39
  19 │ Ahith         39
  20 │ Korass        39
  21 │ Gokelis       39
  22 │ Ozatosh       39
  23 │ Emitrix       39
  24 │ Isim          39
  25 │ Ophuqiohn     39
  26 │ Terias        39
  27 │ Izohr         39
  28 │ Uphanneas     39
  29 │ Ossaem        39
  30 │ Enyll         39
  31 │ Aheronin      39
  32 │ Sumorith      39
  33 │ Eluhion       39