Das PPCG-Handicap-System

35

Wie wir alle wissen, Meta ist überfüllt mit Beschwerden über Scoring Code-Golf zwischen Sprachen (ja, jedes Wort eine separate Verbindung, und diese können nur die Spitze des Eisbergs sein).

Angesichts der großen Eifersucht gegenüber denjenigen, die sich tatsächlich die Mühe gemacht haben, die Pyth-Dokumentation nachzuschlagen, fand ich es schön, eine etwas konstruktivere Herausforderung zu haben, passend zu einer Website, die sich auf Code-Herausforderungen spezialisiert hat.


Die Herausforderung ist ziemlich einfach. Als Eingabe haben wir den Namen der Sprache und die Anzahl der Bytes . Sie können diese als Funktionseingaben stdinoder als Standardeingabemethode für Ihre Sprachen verwenden.

Als Ausgabe haben wir eine korrigierte Byteanzahl , dh Ihre Punktzahl mit dem angewendeten Handicap. Die Ausgabe sollte jeweils die Funktionsausgabe stdoutoder die Standardausgabemethode Ihrer Sprache sein. Die Ausgabe wird auf ganze Zahlen gerundet, weil wir Tiebreaker lieben.

Mit der hässlichsten, gemeinsam gehackten Abfrage ( Link - zögern Sie nicht, sie zu bereinigen) habe ich es geschafft, einen Datensatz (zip mit .xslx, .ods und .csv) zu erstellen , der eine Momentaufnahme aller Antworten auf Fragen enthält . Sie können diese Datei verwenden (und annehmen , dass es zu Ihrem Programm zur Verfügung steht, zum Beispiel in dem gleichen Ordner ist) oder diese Datei in ein anderen herkömmlichen Format konvertieren ( .xls, .mat, .savusw. - aber es kann nur die Originaldaten enthalten!). Der Name sollte QueryResults.extbei extder gewünschten Erweiterung bleiben .


Nun zu den Einzelheiten. Für jede Sprache gibt es einen Boilerplate- Bund einen Ausführlichkeitsparameter V. Zusammen können sie verwendet werden, um ein lineares Modell der Sprache zu erstellen. Sei ndie tatsächliche Anzahl von Bytes und cdie korrigierte Punktzahl. Mit einem einfachen Modell erhalten n=Vc+Bwir für die korrigierte Punktzahl:

    n-B
c = ---
     V

Einfach genug, oder? Nun zur Bestimmung Vund B. Wie zu erwarten, werden wir eine lineare Regression durchführen, genauer gesagt eine linearen Regression mit der Gewichtung der kleinsten Quadrate. Ich werde die Details dazu nicht erklären - wenn Sie nicht sicher sind, wie Sie das machen sollen, ist Wikipedia Ihr Freund , oder wenn Sie Glück haben, die Dokumentation Ihrer Sprache.

Die Daten lauten wie folgt. Jeder Datenpunkt ist ndie Byteanzahl und die durchschnittliche Byteanzahl der Frage c. Um Stimmen zu erhalten, werden die Punkte mit der Anzahl der Stimmen plus eins gewichtet (um 0 Stimmen zu erhalten), nennen wir das v. Antworten mit negativen Stimmen sollten verworfen werden. In einfachen Worten sollte eine Antwort mit 1 Stimme dasselbe wie zwei Antworten mit 0 Stimmen zählen.

Diese Daten werden dann unter n=Vc+BVerwendung einer gewichteten linearen Regression in das vorgenannte Modell eingepasst .


Zum Beispiel die Daten für eine bestimmte Sprache gegeben

n1=20, c1=8.2, v1=1
n2=25, c2=10.3, v2=2
n3=15, c3=5.7, v3=5

Nun, wir komponieren die entsprechenden Matrizen und Vektoren A, yund Wmit unseren Parametern im Vektor

  [1 c1]    [n1]    [1 0 0]  x=[B]
A=[1 c2]  y=[n2]  W=[0 2 0],   [V]
  [1 c3]    [n3]    [0 0 5]

Wir lösen die Matrixgleichung (mit 'der Transponierung)

A'WAx=A'Wy

für x(und folglich bekommen wir unsere Bund VParameter).


Ihre Punktzahl wird die Ausgabe Ihres Programms sein, wenn Sie Ihren eigenen Sprachnamen und Ihre Bytecount-Zahl angeben. Ja, diesmal können sogar Java- und C ++ - Benutzer gewinnen!

WARNUNG: Die Abfrage generiert ein Dataset mit vielen ungültigen Zeilen, da Benutzer die "coole" Header-Formatierung verwenden und ihre Fragen als . Der von mir bereitgestellte Download hat die meisten Ausreißer entfernt. Verwenden Sie NICHT die mit der Abfrage bereitgestellte CSV.

Viel Spaß beim Codieren!

Sanchises
quelle
3
s / schauen die Pyth Dokumentation / sorgfältig studieren , die auf zwei vorhandenen Stücke von Jelly Dokumentation
lirtosiast
Ihre Abfrage scheint nicht zwischen Perl 5 und Perl 6 zu unterscheiden. Dies ähnelt dem Nichtunterscheiden von C ++ von Haskell.
Brad Gilbert b2gills
@ BradGilbertb2gills Ich weiß - es macht eine Menge schrulliger Dinge, vor allem, weil die Leute beim Formatieren verrückt werden. Fühlen Sie sich frei, dies zu verbessern, aber im Moment ist es ein Kompromiss zwischen fehlender Versionsnummerierung und den genannten Sprachen C++ <s>6 bytes</s>. Außerdem habe ich bis heute noch nie T-SQL gemacht und ich bin schon beeindruckt, dass ich es geschafft habe, den bytecount zu extrahieren.
Sanchises
Können wir Ausreißer entfernen, dh alle Sprachen mit nur einem Eintrag (normalerweise falschen Sprachnamen) oder Sprachen mit mehr als 10.000 Bytes?
Robert Fraser
@RobertFraser Ich dachte, das wäre zu viel für eine einzelne Herausforderung. Ich werde die Datendatei reparieren, siehe Bearbeiten.
Sanchises

Antworten:

21

Mathematica, 244.719 (245 Byte)

f[l_,n_]:=x/.Solve[d=Rest@Import@"QueryResults.csv";LinearModelFit[#.#2/Tr@#&@@{#~Max~-1&/@#4+1,#3}&@@Thread@#&/@{#,#~Cases~{_,l,__}}&/@d~GroupBy~Last/@#[[;;,1,5]],x,x,Weights->Tr/@#[[;;,;;,4]]]&[d~Cases~{_,l,_,v_/;v>=0,_}~GatherBy~Last]@x==n,x]

Testfall

f["mathematica", n]   (* { .820033 (n + 53.4263) } *)
f["mathematica", 245] (* { 244.719 } *)

Was ist mit anderen Sprachen?

f["c++", n]           (* { .821181 (n - 79.5437) } *)
f["java", n]          (* { .717579 (n - 56.0858) } *)
f["cjam", n]          (* { 2.21357 (n + 2.73772) } *)
f["pyth", n]          (* { 4.52194 (n - 8.82806) } *)

Alternatives Modell :log(c)=log((n-B)/V)

Ein bemerkenswertes Merkmal von Codegolf (und wahrscheinlich anderen Codierungsproblemen) ist, dass die Verteilung der Programmlängen tendenziell exponentiell ist (im Gegensatz zur gleichmäßigen Verteilung). Daher log(n)=log(Vc+B)ist es viel wahrscheinlicher, dass das Modell die Einflüsse zwischen großen cund kleinen Punkten ausgleicht c.

Wie wir in den folgenden Diagrammen sehen können, eignet sich die Punkteverteilung zur Anpassung an die logarithmische Skala.


Ergebnisse des neuen Modells

Language       V       B

Python       1.365   -19.4    
Javascript   1.002     1.6
Ruby         0.724     1.7
Perl         1.177   -32.7
C            1.105     1.5
Haskell      1.454   -24.5
Mathematica  1.319   -39.7
PHP          1.799   -62.0
Java         1.642     4.4
C#           1.407     4.5

CJam         0.608   -12.5
Pyth         0.519   -11.4
Golfscript   0.766   -18.0
J            0.863   -21.4
APL          0.744   -17.7
K            0.933   -23.3
Retina       1.322   -37.9
MATL         0.762   -13.3
Jelly        0.965   -23.8

Wir haben zwei außergewöhnliche Sprachen gefunden - Ruby mit V=0.724und Retina mit V=1.322und ein Kriterium dafür, dass es sich um eine beliebte Golfsprache handelt - mit einem großen negativen Boilerplate.

njpipeorgan
quelle
@sanchises Soweit so gut, außer dass Sie Semikolons als Begrenzer verwenden csv.
njpipeorgan
Das ist Microsoft Excel für Sie. Offensichtlich ist es zu schwierig, als CSV zu speichern.
Sanchises
Anscheinend hat CJam also eine negative Länge. Interessant.
PurkkaKoodari
@ Pietu1998 Lineares Modell ist glaube ich nicht so genau.
njpipeorgan
@ Pietu1998 Kein Wunder, da Golfsprachen im Allgemeinen implizite Eingaben akzeptieren und möglicherweise implizite Ausgaben zurückgeben. Beachten Sie, dass "Boilerplate-Länge" für den Durchschnitt definiert ist und nicht für eine ideale Sprache ohne Boilerplate. Ich bin tatsächlich positiv überrascht, wie gut dieses einfache Modell zu sein scheint, wenn man sich diese Ergebnisse ansieht.
Sanchises
3

Python3, 765,19 (765) Bytes

Wahrscheinlich etwas Platz zum Golfen hier. Benötigt Numpy für Matrixmaterial. Liest wie folgt aus stdin: [lang] [bytes / n]. Stoppt beim Senden von q.

import numpy as n,csv
L={};Q={};X={};D=n.dot;f=open('QueryResults.csv',encoding="utf8");R=csv.reader(f);f.readline();Z=list.append;M=n.matrix
for r in R:
 if r[1] not in L:L[r[1]]=[]
 if r[4] not in Q:Q[r[4]]=[]
 Z(L[r[1]],r);Z(Q[r[4]],r)
for l in L:
 b=[];a=[];v=[];t=[]
 for r in L[l]:
  if int(r[3])>-1:
   Z(b,int(r[2]));o=[]
   for q in Q[r[4]]:Z(o,int(q[2]))
   Z(a,sum(o)/len(o));Z(v,int(r[3])+1)
 for k in a:Z(t,[1,k])
 if len(t)<1:continue
 A=M(t);T=A.transpose();W=n.diag(v);y=M(b).reshape((len(b),1));e=D(D(T,W),A)
 if n.linalg.det(e)==0:continue
 i=n.linalg.inv(e);X[l]=D(i,D(D(T,W),y))
p=input()
while(p!="q"):
 S=p.split()
 if S[1]=='n':print("(n-("+str(X[S[0]].item(0))+"))/"+str(X[S[0]].item(1)))
 else:print(str((int(S[1])-X[S[0]].item(0))/X[S[0]].item(1)))
 p=input()

Ergebnisse

Ich könnte irgendwann etwas falsch gemacht haben; Ich erhalte andere Ergebnisse als die Mathematica-Antwort:

python3 808 -> 765.19
python3 n   -> (n-(32.41))/1.01

c++ n        -> (n-(71.86))/1.17
cjam n       -> (n-(-14.09))/0.51
java n       -> (n-(18.08))/1.64
pyth n       -> (n-(1.42))/0.28
jelly n      -> (n-(-4.88))/0.34
golfscript n -> (n-(-0.31))/0.44
Jodler
quelle