Golf Integer Otak-Keripik

28

Bilangan bulat membosankan untuk diwakili dalam Brain-Flak . Ada 8 operator:

()      Evaluates to 1, but does not push anything on any stack
[]      Evaluates to an indeterminate value for the purposes of this question
{}      Removes the top of the stack and evaluates to it
<>      Switches to or back from the alternate stack and evaluates to zero
(foo)   Pushes the value of the expression foo to the stack and evaluates to it
[foo]   Evaluates to the negation of foo
{foo}   Evaluates the expression foo until the top of the stack is zero
<foo>   Evaluates to zero but executes foo anyway

foodapat terdiri dari beberapa operator, dalam hal ini mereka dievaluasi dan dijumlahkan. Misalnya (()())mendorong 2ke tumpukan (dan mengevaluasi 2juga).

Jelas, (()...())mekanisme ini tidak berguna dalam Code Golf karena jumlah besar akan membutuhkan n*2+2byte untuk diwakili. Oleh karena itu, tantangan Anda adalah menulis program atau fungsi yang akan menghasilkan sesedikit mungkin byte program Brain-Flak yang akan mendorong bilangan bulat positif yang diberikan nke tumpukan aktif. Program ini tidak boleh membuat asumsi tentang isi tumpukan yang ada, sehingga tidak boleh meninggalkan tumpukan dipertukarkan atau menambah atau menghapus nilai tambahan dari tumpukan.

Meskipun program atau fungsi Anda harus mampu mengembalikan program Brain-Flak yang bekerja untuk semua input dari 1 hingga 1.000.000, pemenangnya adalah program atau fungsi yang menghasilkan set terkecil dari program Brain-Flak yang sesuai untuk semua 1.061 bilangan prima antara 1.000 dan 1.000 10.000 . Anda harus mencatat ukuran total output Anda untuk 1061 input tersebut sebagai bagian dari kiriman Anda. Program atau fungsi Anda dapat menerima integer dan mengembalikan program (string) Brain-Flak dalam format I / O yang dapat diterima. Ikatan akan rusak menggunakan ukuran program atau fungsi Anda.

Neil
sumber
4
Sama seperti catatan: jumlah program panjang yang valid 2nadalah 4^n catalan(n).
Leaky Nun
2
Hmm, saya suka tantangannya, tapi saya pikir itu harus dinilai pada bilangan bulat yang tidak diketahui. Jika tidak, program bilangan bulat yang diberi nilai dapat menjadi brute paksa dan bilangan bulat lainnya dibiarkan begitu saja (()()()...()). Plus, jika Anda hanya menggunakan bilangan prima, itu mungkin kehilangan beberapa optimasi yang mungkin untuk komposit.
DJMcMayhem
Juga, mengapa tidak []terdefinisi untuk tantangan ini? Saya merasa aneh menerapkan 7 dari 8 operator. Either way, tantangan keren, saya merasa terhormat seseorang akan menulis tantangan yang terinspirasi oleh bahasa saya sendiri!
DJMcMayhem
2
@DJMcMayhem Saya ingin orang dapat menghitung skor mereka sendiri. Semua bilangan prima yang relevan adalah satu lebih dari bilangan gabungan, sehingga harus ada banyak optimisasi potensial. Juga, saya tidak ingin orang bergantung pada nilai tertentu []dalam jawaban mereka.
Neil
1
@YetiCGN Ukuran skrip hanya dianggap sebagai pengikat.
Neil

Jawaban:

16

Python 2, 59394 59244 58534 58416 58394 58250

Ok di sini adalah solusi saya.

import re
import math

cache = {0:"<()>"}

def find(x,i,j):
    return i*((x**2+x)/2)+(j+1)*((x**2-x)/2)

def solve(x, i, j):
    a = (i + j + 1)/2.
    b = (i - j - 1)/2.
    c = -x
    return (-b + math.sqrt(b**2 - 4*a*c))/(2*a)

def size(i,j=0):
    return 4*(i+j)+14

def polynomials(n):
    upperBound = int(4*math.log(n,2))
    i = 0
    answers = []
    while size(i) < upperBound:
        for j in range(i):
            sol = int(solve(n, i-j, j)+.5)
            if find(sol, i-j, j) == n:
                answers.append((sol, i-j, j))
        i += 1
    return answers

def complement(character):
        dict = {"(":")","{":"}","<":">","[":"]",")":"(","}":"{",">":"<","]":"["}
        return dict[character]

def findMatch(snippet, index):
        increment = 1 if snippet[index] in "({<[" else -1
        stack = []
        if snippet[index] in "(){}<>[]":
                stack.append(snippet[index])
        while len(stack) > 0 and index + increment < len(snippet):
                index += increment
                if snippet[index] in "(){}<>[]":
                        if complement(snippet[index]) == stack[-1]:
                                stack = stack[:-1]
                        else:
                                stack.append(snippet[index])
        return index

def isPrime(n):
    return not [0 for x in range(2,int(n**.5)+1) if n%x==0] and n>1

def getPrimeFactors(n):
    return [x for x in range(2,n/2) if n%x==0 and isPrime(x)]

def divHardcode(n,m):
    assert n%m == 0
    assert m != 1
    assert n != 1
    binary = bin(m)[3:]
    return (binary.count("1")+len(binary))*"("+getBF(n/m)+")"*binary.count("1")+binary.replace("1","){}{}").replace("0","){}")

def isTriangular(n):
    #Triangles must be between sqrt(2n) and cbrt(2n)
    if n < 0: return isTriangular(-n)
    for x in range(int((2*n)**(1/3.)),int((2*n)**.5)+1):
        if (x**2+x) == 2*n:
            return True
    return False

def getTriangle(n):
    if n < 0: return -getTriangle(-n)
    #Triangles must be between sqrt(2n) and cbrt(2n)
    for x in range(int((2*n)**(1/3.)),int((2*n)**.5)+1):
        if (x**2+x) == 2*n:
            return x
    #If we don't find one we made a mistake
    assert False

def getSimpleBF(n):
    if n in cache:return cache[n]
    if n < 0:
        # There is room for better solutions here
        return "["+getSimpleBF(-n)+"]"
    elif n == 0:
        return ""
    elif n < 6:
        return "()"*n
    #Non-edge cases
    solutions = []
    factors = getPrimeFactors(n)
    if n >= 78 and isTriangular(n):
        solutions.append(
           min([push(getTriangle(n))+"{({}[()])}{}","<"+push(getTriangle(n)+1)+">{({}[()])}{}"],key=len)
        )
    polynomialSolutions = polynomials(n)
    for polynomial in polynomialSolutions:
        solutions.append("<%s>{%s({}[()])%s}{}"%(push(polynomial[0]),"({})"*polynomial[1],"({})"*polynomial[2]))
        #Mod 3 tricks
    if n % 3 == 2:
       solutions.append(("((%s)()){}{}")%getBF(n/3))
    elif n % 3 == 1:
       solutions.append(("((%s)()()){}{}")%getBF(n/3-1))
    #Basic solutions
    if isPrime(n):
        solutions.append(getSimpleBF(n-1) + "()")
    else:
        #TODO multithread
        solutions += map(lambda m:divHardcode(n,m),factors)
    return min(solutions,key=lambda x:len(unpack(x)))

def getBF(n):
    if n in cache: return cache[n]
    result = getSimpleBF(n)
    index = n - 1
    while index > n-(len(result)/2):
        score = getSimpleBF(index)+getSimpleBF(n-index)
        if len(score) < len(result):result = score
        index -= 1
    index = n + 1
    while index < n+(len(result)/2):
        score = getSimpleBF(index)+getSimpleBF(n-index)
        if len(score) < len(result):result = score
        index += 1
    cache[n] = result
    return result

def unpack(string):
    reMatch = re.match("\(*<",string)
    if reMatch:
        location =reMatch.span()
        return string[location[1]:findMatch(string,location[1]-1)] +string[:location[1]-1] + string[findMatch(string,location[1]-1)+1:]
    return string

def push(n):
    return unpack("("+getBF(n)+")")

def kolmo(string):
    code = push(ord(string[-1]))
    stringVector = map(ord,string)
    for x,y in zip(stringVector[-1:0:-1],stringVector[-2::-1]):
        code = "("+code+getBF(y-x)+")"
    code = code.replace("<()>)",")")
    return code

def kolmo(stringVector):
    code = push(stringVector[-1])
    for x,y in zip(stringVector[-1:0:-1],stringVector[-2::-1]):
        code = "("+code+getBF(y-x)+")"
    code = code.replace("<()>)",")")
    return code


if __name__ == "__main__":
    import primes
    sum = 0
    for prime in primes.nums:
        print push(prime)
        sum += len(push(prime))
    print sum

Fungsi yang relevan adalah push(n). Untuk menyebutnya cukup panggil push pada integer yang ingin Anda wakili.

Penjelasan

Optimalisasi utama yang dilakukan oleh program ini adalah multiplikasi hard-coding. Gagasan multiplikasi hardcoding cukup sederhana. Anda menekan angka lalu pop dan mendorongnya untuk membuat nilai baru. Misalnya untuk mengalikan dua, Anda dapat menggunakan kode berikut di ((n){})mana n kode menghasilkan angka tertentu. Ini berfungsi karena keduanya (n)dan {}memiliki nilai n.

Ide sederhana ini dapat dibuat lebih kompleks untuk jumlah yang lebih besar. Ambil contoh 5 ditemukan beberapa waktu lalu bahwa cara terbaik untuk mengalikan lima adalah (((n)){}){}{}. Kode ini membuat dua salinan dari n mengalikan satu dengan 4 dan menambahkan dua. Menggunakan strategi yang sama saya membuat setiap perkalian berdasarkan representasi biner angka. Saya tidak akan masuk ke rincian tentang bagaimana ini bekerja sekarang, tetapi saya melakukan ini dengan memotong yang pertama dari representasi biner dan mengganti 0 dengan ){}dan 1 dengan){}{}. Itu kemudian memastikan bahwa n didorong jumlah waktu yang tepat dan menyeimbangkan semua tanda kurung. (Jika Anda ingin tahu bagaimana ini dilakukan, Anda dapat melihat kode saya). Jika Anda ingin tahu mengapa ini berhasil tanyakan pada saya di komentar. Saya tidak berpikir ada orang yang benar-benar membaca semua pembaruan untuk posting saya jadi saya tinggalkan penjelasannya.

Ketika algoritma berusaha menemukan hardcode perkalian, ia mencoba semua faktor prima bilangan. Ia mengabaikan faktor-faktor komposit karena pada satu titik faktor-faktor komposit selalu dapat dinyatakan lebih ringkas sebagai faktor pribadinya sendiri, tidak diketahui apakah ini masih benar.

Mekanisme penghematan byte lainnya adalah pencari solusi polinomial. Ada beberapa bentuk polinomial yang mudah direpresentasikan dengan loop pengurang. Polinomial ini termasuk, tetapi tidak terbatas pada, angka poligon. Pengoptimalan ini menemukan polinomial yang sesuai dengan formulir dan membuat kode yang membuatnya.

Keluaran

tempat sampah

Wisaya Gandum
sumber
"apakah n lebih besar atau lebih kecil dari n +1" ??
Sparr
@Sparr apakah interpretasi nlebih besar atau lebih kecil darin+1
Wisaya Gandum
Anda harus melepas tanda garis dari if n % 3 == 2: ke ujung fungsi itu dengan satu tingkat.
user202729
13

Brain-Flak, 64664

Cobalah secara Online!

Ini kode beranotasi saya

({}<
 ((((()()()()()){}){}){}()) #41
>)
{
 (({})[()()()()()()])
 ([({}<(())>)](<>)){({}())<>}{}<>{}{}<>(({})){(<{}({}<>)>)}{}({}<>)
 {((< #IF
  {} 
  {({}[()]< #FOR
   ((((()()()()()){}){}){}()) #41
   (({})[()])                 #40
  >)}{}
 >))}{}
 (({}))
 #MOD2
 {(<
  ({}<(())>)({<({}[()]<>)><>(()[{}])<><({}<>)>}{}<({}<>)><>)<>({}<>)
  {((<{}({}< #IF
   {}
   (((()()()()())({})({})({}){})({})({})({}){})  #125
   (({})[()()])                                  #123
   ((((()()()()()){}){}){}())                    #41
   <>
   ((((()()()()()){}){}){})                      #40
   <>
   >)

  >))}{}{}
 >)}{}
 #MOD2 (number 2)
 (({}))
 ({}(())){({}[()]<>)<>(()[{}])<>({}<>)}{}
 (({})<([{}]{})>)
 {
  ({}[()]<<>
    ((((()()()()()){}){}){}) #40
    (({})())                 #41
   <>>)
 }{}
}{}
<>{({}<>)<>}<>((((()()()()()){}){}){})

Penjelasan

Ini hanya mengimplementasikan dua aturan seperti sekarang:

  • Jika n habis dibagi dua (n/2){}

  • Jika n tidak habis dibagi dua, kembali n-1()

Itu juga hardcodes semua angka lebih kecil dari 6.

Wisaya Gandum
sumber
Sepertinya cek untuk pembagian oleh tiga harus mengurangi skor sedikit
ASCII-hanya
@ ASCII-saja saya benar-benar mengimplementasikannya dan meningkatkan jumlah byte. Saya sedang mengerjakan cara mengimplementasikan versi lebih pintar dari keterbagian oleh tiga.
Wheat Wizard
Ok, menggunakan Brain-Flak untuk membuat program yang menghasilkan angka Brain-Frak. Bagus.
Draco18s
10

Perl, 59222 59156 58460 karakter

  • n() (11322660 karakter)
  • (n){}() (64664 karakter)
  • ((n)){}{} (63610 karakter)
  • ((n)()){}{} (63484 karakter) - ini adalah perhitungan baru
  • (n){({}[()])}{} (60748 karakter)
  • n[m] (62800 karakter)
  • (n){m({}[l])}{} (58460 karakter) - ini adalah perhitungan baru

Rumus untuk perhitungan terakhir adalah n(n/l+1)/2+mn/l. Saya sudah mencoba beberapa perhitungan lain tetapi tidak lagi membantu untuk hasil yang diberikan. Program ini benar-benar menghasilkan semua nilai hingga 9999 tetapi kemudian mendaftar bilangan prima yang diberikan dan total panjangnya.

@primes = (<list of the 4-digit prime numbers here>);
@numbers = ();
for ($i = 1; $i < 10000; $i++) {
  $numbers[$i] = "()" x $i; # default calculation
}
for ($i = 2; $i < 10000; $i++) {
  for ($j = 1; $j < 8; $j++) {
    &try($i, "$numbers[$i+$j]\[$numbers[$j]]");
  }
  &try($i + 1, "$numbers[$i]()");
  &try($i * 2, "($numbers[$i]){}");
  &try($i * 3, "(($numbers[$i])){}{}");
  &try($i * 3 + 2, "(($numbers[$i])()){}{}");
  for ($l = 1; $l * $l < $i; $l++) { 
    unless ($i % $l) { 
      for ($j = 0; ($k = (($i + $j + $j) * $i / $l + $i) / 2) < 10000; $j++) { 
        &try($k, "($numbers[$i]){$numbers[$j]({}[$numbers[$l]])}{}");
      } 
    } 
  } 
}
$len = 0;
foreach (@primes) {
  print "($numbers[$_])\n";
  $len += 2 + length $numbers[$_];
}
print "$len\n";
sub try {
  ($n, $s) = @_;
  $numbers[$n] = $s if (length($numbers[$n]) > length $s);
}
Neil
sumber
Bisakah Anda memberikan tautan ke output?
DJMcMayhem
@DJMcMayhem Ups, saya tidak sengaja merusak daftar bilangan prima saya, membuat jumlah karakter saya tidak valid.
Neil
@Linus ((X) ()) {} {} mendorong X, lalu menambahkan 1, mendorong hasilnya, lalu muncul X + 1 dan X. Total 3X + 2. Saya pikir saya sudah mencoba formula lain di Try It Online tetapi saya bisa mengecek apakah Anda mau.
Neil
@Neil Kesalahan saya ... Ini terlihat bagus tapi apa sebenarnya yang merusak bilangan prima Anda?
Linus
1
@Neil saya mendapatkan 58158 ketika saya menambahkan &try($i * $i, "$numbers[$i]{({})({}[()])}{}");, yang turun ke 58032 ketika saya juga menambahkan &try((3 * $i * $i - $i) / 2, "$numbers[$i]{({})({}[()])({})}{}");(angka persegi / pentagonal) - itu dari sini
ASCII-only
5

Python, 59136 58676 karakter

Fungsi golf nomor Brainflak:

m=11111
R=range(0,m)
R[1]="()"
R[2]="()()"
l=2
def a(v,r):
 if v>0 and v<m:
  if isinstance(R[v],int) or len(r)<len(R[v]):
   R[v]=r
   if v<R[0]:
    R[0]=v
def s(v,k):
 S=0
 while v>0:
  S+=v
  v-=k
 return S
p=lambda r:"("+r+")"
w=lambda r:"{({}["+r+"])}{}"
def q(r,v):
 for i in range(1,v):
  r="("+r+")"
 for i in range(1,v):
  r+="{}"
 return r
def e(r,v,k):
 for i in range(0,k):
  r=q(r,v)
 return r
while l<m:
 R[0]=l+1
 a(l*2,q(R[l],2)) 
 a(l*3,q(R[l],3))
 a(l*5,q(R[l],5))
 a(l*7,q(R[l],7))
 for i in range(1,l):
  a(l+i,R[l]+R[i])
  a(l-i,R[l]+"["+R[i]+"]")
  if l%i==0:
   t=s(l-i,i)
   a(s(l,i),p(R[l])+w(R[i]))
   a(l+2*t,p(R[l])+q(w(R[i]),2))
   a(l+4*t,p(R[l])+e(w(R[i]),2,2))
   a(l+8*t,p(R[l])+e(w(R[i]),2,3))
   a(l+16*t,p(R[l])+e(w(R[i]),2,4))
   a(l+32*t,p(R[l])+e(w(R[i]),2,5))
   a(l+64*t,p(R[l])+e(w(R[i]),2,6))
   a(l+128*t,p(R[l])+e(w(R[i]),2,7))
   a(l+3*t,p(R[l])+q(w(R[i]),3))
   a(l+9*t,p(R[l])+e(w(R[i]),3,2))
   a(l+27*t,p(R[l])+e(w(R[i]),3,3))
   a(l+5*t,p(R[l])+q(w(R[i]),5))
   a(l+6*t,p(R[l])+q(q(w(R[i]),3),2))
   a(l+10*t,p(R[l])+q(q(w(R[i]),5),2))
   a(l+15*t,p(R[l])+q(q(w(R[i]),5),3))
   a(l+12*t,p(R[l])+q(q(q(w(R[i]),3),2),2))
   a(l+18*t,p(R[l])+q(q(q(w(R[i]),3),3),2))
   a(l+20*t,p(R[l])+q(q(q(w(R[i]),5),2),2))
   a(l+24*t,p(R[l])+q(q(q(q(w(R[i]),3),2),2),2))
   a(l+36*t,p(R[l])+q(q(q(q(w(R[i]),3),3),2),2))
   a(l+40*t,p(R[l])+q(q(q(q(w(R[i]),5),2),2),2))
 l=R[0]
f=lambda v:p(R[v])

Iterasi bilangan prima:

def isPrime(v):
 i=2
 while i*i<=v:
  if v%i==0:
   return False
  i+=1
 return True

for i in range(1000,10000):
 if isPrime(i):
  print f(i)

Keluaran:

Pastebin

Penjelasan:

Kami mempopulasikan daftar R representasi Brain-flak yang mengevaluasi bilangan bulat individual pada rentang yang lebih besar dari yang diperlukan [1, m -1] untuk mendefinisikan fungsi kami f . Representasi dibentuk dengan mengambil representasi terendah yang tidak digunakan (diindeks oleh l ) dan membentuk banyak representasi baru darinya, hanya menyimpan yang terpendek. Representasi terendah yang tidak digunakan mengasumsikan bahwa semua angka 1 hingga l telah ditetapkan sebagai representasi, dan bahwa representasi ini telah digunakan untuk menghasilkan angka baru. Jika nilai kurang dari l mendapat representasi yang lebih pendek, kita harus kembali dan mereproduksi angka mulai dari titik itu. Fungsi f menghasilkan program menyimpan nomor ke tumpukan dengan menambahkan tanda kurung.

Saya tidak tahu Brainflak ketika saya memulai ini, dan sangat menghargai jawaban Eamon Olive karena menunjukkan rumus untuk angka segitiga. Sebagian besar saya sudah menggeneralisasi penjumlahan dan tanpa henti memeriksa jumlah dan perbedaan. Menambahkan banyak kelipatan jumlah memiliki pengaruh besar.

Bagi mereka yang peduli, ini adalah kode awal yang saya gunakan untuk melihat formula mana yang layak.

Rumus Representasi:

  1. Perkalian dengan bilangan prima kecil:
    (X){}
    ((X)){}{}
    ((((X)))){}{}{}{}
    ((((((X)))))){}{}{}{}{}{}
  2. Tambahan X + Y :
    XY
  3. Pengurangan X - Y :
    X[Y]
  4. Penjumlahan ke dan termasuk X kenaikan Y :
    (X){({}[Y])}{}
  5. Kelipatan penjumlahan ke X selisih Y , ditambah X :
    (X)({({}[Y])}{}){}
    (X)(({({}[Y])}{})){}{}
    (X)(({({}[Y])}{}){}){}
    dll ...
Linus
sumber
Saya pikir 5 * tidak membantu, tetapi sekarang saya melihatnya menghemat 10 karakter pada jawaban saya. Saya pikir saya sudah mencoba penjumlahan itu, tapi saya akan mengecek!
Neil
Jumlah penambahan dan kelipatan menyelamatkan saya 46 byte, dan bahkan kemudian saya harus membilas dan mengulangi tiga kali untuk menangkap mereka semua.
Neil
Ternyata jika saya menggunakan pengurangan maka saya tidak menggunakan 5 * lagi.
Neil
4

Lua 5.3, 57522

Saya sebenarnya mulai mengerjakan ini kembali ketika pertanyaan diposting, tetapi lupa tentang hal itu sampai ulang tahun Brain-Flak.

-- 64 gives all results through 10000 (should run in about 1 second)
-- 78 gives all results through 100000 (should run in about 20 seconds)
-- 90 gives all results through 1000000 (should run in about 200 seconds)
-- Note: Timings may not be accurate, as the are not updated every time new cases are added.

local k_max_len = 64
local k_limit = 10000

local pre = os.clock()

local function compute_multiplier_helper(prefix, suffix, m)
  if m == 2 then
    prefix[#prefix + 1] = "("
    suffix[#suffix + 1] = "){}"
  elseif m % 2 == 0 then
    prefix[#prefix + 1] = "("
    compute_multiplier_helper(prefix, suffix, m // 2)
    suffix[#suffix + 1] = "){}"
  else
    suffix[#suffix + 1] = ")"
    compute_multiplier_helper(prefix, suffix, m - 1)
    prefix[#prefix + 1] = "("
    suffix[#suffix + 1] = "{}"
  end
end

local function compute_multiplier(m)
  local prefix = {}
  local suffix = {}
  compute_multiplier_helper(prefix, suffix, m)
  return table.concat(prefix), table.concat(suffix)
end

local multipliers = {}
for m = 2, k_limit do
  -- Including all factors, not just primes.
  -- This did improve a few numbers, although none in the ppcg test set.
  local prefix, suffix = compute_multiplier(m)
  local mult = {prefix = prefix, suffix = suffix, m = m, cost = #prefix + #suffix}
  table.insert(multipliers, mult)
end
table.sort(multipliers, function(a, b) return a.cost < b.cost end)

local poly_multipliers = {}
poly_multipliers[1] = {m = 1, s = "({})", l = 4}
for m = 2, k_limit do
  local prefix, suffix = compute_multiplier(m)
  local s = prefix .. "({})" .. suffix
  assert(#s <= 4 * m)
  poly_multipliers[m] = {m = m, s = s, l = #s}
end
poly_multipliers[k_limit + 1] = {m = 0, s = "", l = 0}

table.sort(poly_multipliers, function(a, b) return a.l < b.l end)

local pcache = {}
local plen_cache = {}

local function register_push(prefix, suffix, value, pvalue)
  if value > 1500000 or value < -1500000 then return end
  local old_res = pcache[value]
  if old_res == nil then
    local res = {prefix = prefix, suffix = suffix, value = value, pvalue = pvalue}
    pcache[value] = res
    local length = #prefix + #suffix
    local lcache = plen_cache[length]
    if lcache == nil then
      lcache = {}
      plen_cache[length] = lcache
    end
    lcache[#lcache + 1] = res
  end
end

local function get_pushes(length)
  return ipairs(plen_cache[length] or {})
end

register_push("", "()", 1, 0)
register_push("", "<()>", 0, 0)

local function triangle(n)
  return (n * (n + 1)) // 2
end

local function process(length)
  -- basic
  for _, res in get_pushes(length - 2) do
    register_push(res.prefix, res.suffix .. "()", res.value + 1, res.pvalue)
    register_push(res.prefix, "[" .. res.suffix .. "]", -res.value, res.pvalue)
  end

  -- multiplication by constant (precomputed)
  for _, mult in ipairs(multipliers) do
    local cost = mult.cost
    if length - cost >= 4 then
      local m, prefix, suffix = mult.m, mult.prefix, mult.suffix
      for _, pus in get_pushes(length - cost) do
        local name = prefix .. pus.suffix .. suffix
        register_push(pus.prefix, name, pus.value * m, pus.pvalue)
      end
    else
      break
    end
  end

  -- residue 2 mod3 trick (Neil)
  -- ((n)()){}{}
  --  (n)        -- push n
  -- (   ())     -- push n + 1
  --        {}{} -- (n + 1) + (n + 1) + n
  if length - 10 >= 2 then
    for _, res in get_pushes(length - 10) do
      local name = "((" .. res.suffix .. ")()){}{}"
      register_push(res.prefix, name, 3 * res.value + 2, res.pvalue)
    end
  end

  -- residue 1 mod3 trick (Wheat Wizard)
  -- ((n)()()){}{}
  --  (n)          -- push n
  -- (   ()())     -- push n + 2
  --          {}{} -- (n + 2) + (n + 2) + n
  -- not useful, but fast...
  if length - 12 >= 2 then
    for _, res in get_pushes(length - 12) do
      local name = "((" .. res.suffix .. ")()()){}{}"
      register_push(res.prefix, name, 3 * res.value + 4, res.pvalue)
    end
  end

  -- residue 2 mod5 trick (tehtmi)
  -- (((n)){}()){}{}
  --   (n)           -- push n
  --  (   )          -- push n
  -- (     {}())     -- push 2n + 1
  --            {}{} -- (2n + 1) + (2n + 1) + n
  -- [[
  if length - 14 >= 2 then
    for _, res in get_pushes(length - 14) do
      local name = "(((" .. res.suffix .. ")){}()){}{}"
      register_push(res.prefix, name, 5 * res.value + 2, res.pvalue)
    end
  end
  -- ]]

  -- residue 4 mod5 trick (tehtmi)
  -- (((n)()){}){}{}
  --   (n)           -- push n
  --  (   ())        -- push n + 1
  -- (       {})     -- push 2n + 2
  --            {}{} -- (2n + 2) + (2n + 2) + n
  -- [[
  if length - 14 >= 2 then
    for _, res in get_pushes(length - 14) do
      local name = "(((" .. res.suffix .. ")()){}){}{}"
      register_push(res.prefix, name, 5 * res.value + 4, res.pvalue)
    end
  end
  -- ]]

  -- residue 6 mod7 trick (tehtmi)
  -- ((((n)())){}{}){}{}
  --    (n)              -- push n
  --   (   ())           -- push n + 1
  --  (       )          -- push n + 1
  -- (         {}{})     -- push 3n + 3
  --                {}{} -- (3n + 3) + (3n + 3) + n
  -- [[
  if length - 18 >= 2 then
    for _, res in get_pushes(length - 18) do
      local name = "((((" .. res.suffix .. ")())){}{}){}{}"
      register_push(res.prefix, name, 7 * res.value + 6, res.pvalue)
    end
  end
  --]]

  -- residue 4 mod7 trick (tehtmi)
  -- ((((n))()){}{}){}{}
  --    (n)              -- push n
  --   (   )             -- push n
  --  (     ())          -- push n + 1
  -- (         {}{})     -- push 3n + 2
  --                {}{} -- (3n + 2) + (3n + 2) + n
  -- [[
  if length - 18 >= 2 then
    for _, res in get_pushes(length - 18) do
      local name = "((((" .. res.suffix .. "))()){}{}){}{}"
      register_push(res.prefix, name, 7 * res.value + 4, res.pvalue)
    end
  end
  --]]

  -- residue 2 mod7 trick (tehtmi)
  -- ((((n))){}{}()){}{}
  --    (n)              -- push n
  --   (   )             -- push n
  --  (     )            -- push n
  -- (       {}{}())     -- push 3n + 1
  --                {}{} -- (3n + 1) + (3n + 1) + n
  -- [[
  if length - 18 >= 2 then
    for _, res in get_pushes(length - 18) do
      local name = "((((" .. res.suffix .. "))){}{}()){}{}"
      register_push(res.prefix, name, 7 * res.value + 2, res.pvalue)
    end
  end
  --]]

  -- triangle numbers (?)
  --(n){({}[()])}{}
  --(n)              -- push n
  --   {        }    -- sum and repeat
  --    (      )     -- push
  --     {}[()]      -- top - 1
  --             {}  -- pop 0
  if length - 14 >= 2 then
    for _, res in get_pushes(length - 14) do
      if res.value > 0 then
        local code = "{({}[()])}{}"
        register_push(res.prefix .. "(" .. res.suffix .. ")", code, triangle(res.value - 1), res.pvalue + res.value)
        register_push(res.prefix, "(" .. res.suffix .. ")" .. code, triangle(res.value), res.pvalue)
        register_push("", res.prefix .. "(" .. res.suffix .. ")" .. code, triangle(res.value) + res.pvalue, 0)
      end
    end
  end

  -- negative triangle numbers (tehtmi)
  --(n){({}())}{}
  --(n)            -- push n
  --   {      }    -- sum and repeat
  --    (    )     -- push
  --     {}()      -- top + 1
  --           {}  -- pop 0
  if length - 12 >= 2 then
    for _, res in get_pushes(length - 12) do
      if res.value < 0 then
        local code = "{({}())}{}"
        register_push(res.prefix .. "(" .. res.suffix .. ")", code, -triangle(-res.value - 1), res.pvalue + res.value)
        register_push(res.prefix, "(" .. res.suffix .. ")" .. code, -triangle(-res.value), res.pvalue)
        register_push("", res.prefix .. "(" .. res.suffix .. ")" .. code, -triangle(-res.value) + res.pvalue, 0)
      end
    end
  end

  -- cubic (tehtmi)
  -- (n){(({}[()])){({}[()])}{}}{}
  -- (n^3-3*n^2+8*n-6)/6
  -- (-6 + n*(8 + n*(-3 + n)))/6
  --[[ superceded by negative cubic because 
       it is the same cost of -ncubic(-n)
  if length - 28 >= 2 then
    for _, res in get_pushes(length - 28) do
      if res.value > 0 then
        local code = "{(({}[()])){({}[()])}{}}{}"
        local v = res.value + 1
        v = (-6 + v*(8 + v*(-3 + v)))//6
        register_push(res.prefix .. "(" .. res.suffix .. ")", code, v - res.value, res.pvalue + res.value)
        register_push(res.prefix, "(" .. res.suffix .. ")" .. code, v, res.pvalue)
        register_push("", res.prefix .. "(" .. res.suffix .. ")" .. code, v + res.pvalue, 0)
      end
    end
  end
  --]]

  -- negative cubic (tehtmi)
  -- (n){(({}())){({}())}{}}{}
  -- (n^3-3*n^2+8*n-6)/6
  -- (-6 + n*(8 + n*(-3 + n)))/6
  -- [[
  if length - 24 >= 2 then
    for _, res in get_pushes(length - 24) do
      if res.value < 0 then
        local code = "{(({}())){({}())}{}}{}"
        local v = -res.value + 1
        v = (-6 + v*(8 + v*(-3 + v)))//6
        v = -v
        register_push(res.prefix .. "(" .. res.suffix .. ")", code, v - res.value, res.pvalue + res.value)
        register_push(res.prefix, "(" .. res.suffix .. ")" .. code, v, res.pvalue)
        register_push("", res.prefix .. "(" .. res.suffix .. ")" .. code, v + res.pvalue, 0)
      end
    end
  end
  --]]

  -- polynomial (Wheat Wizard, modified by tehtmi)
  -- <(n)>{A({}[()])B}{} where A, B are ({})({})({})... repeated a, b times
  -- <(n)>                -- push n (without adding)
  --      {          }    -- repeat until top is zero
  --       A              -- top * a
  --        ({}[()])      -- top = top - 1; += top - 1
  --                B     -- (top - 1) * b
  --                  {}  -- pop 0
  -- triangular numbers are with a = b = 0
  -- from B and base:
  -- (n - 1) * (B + 1) * (n - 2) * (B + 1) * ...
  -- (B + 1) * (1 + ... + n - 1)
  -- (B + 1) * n * (n - 1) / 2
  -- from A:
  -- n * A + (n - 1) * A + ...
  -- A * (1 + ... n)
  -- A * (n + 1) * n / 2
  -- total: (B + 1) * n * (n - 1) / 2 + A * (n + 1) * n / 2
  --        [(A + B + 1) * n^2 + (A - B - 1) * n] / 2
  -- S := 4 * (A + B)
  -- [[
  if length - 18 >= 2 then
    for S = 4, length - 14, 4 do
      for _, res in get_pushes(length - 14 - S) do
        if res.value > 0 then
          for _, A in ipairs(poly_multipliers) do
            if A.l > S then
              break
            end
            for _, B in ipairs(poly_multipliers) do
              if A.l + B.l < S then
                -- continue
              elseif A.l + B.l > S then
                break
              else
                local a = A.m
                local b = B.m

                local logic = "{" .. A.s .. "({}[()])" .. B.s .. "}{}"
                local v = res.value
                v = ((a + b + 1) * v * v + (a - b - 1) * v) // 2
                register_push(res.prefix .. "(" .. res.suffix .. ")", logic, v, res.pvalue + res.value)
                register_push(res.prefix, "(" .. res.suffix .. ")" .. logic, v + res.value, res.pvalue)
                register_push("", res.prefix .. "(" .. res.suffix .. ")" .. logic, v + res.value + res.pvalue, 0)
              end
            end
          end
        end
      end
    end
  end
  --]]

  -- negative polynomial (tehtmi)
  -- <(n)>{A({}())B}{}
  -- [[
  if length - 16 >= 2 then
    for S = 4, length - 12, 4 do
      for _, res in get_pushes(length - 12 - S) do
        if res.value < 0 then
          for _, A in ipairs(poly_multipliers) do
            if A.l > S then
              break
            end
            for _, B in ipairs(poly_multipliers) do
              if A.l + B.l < S then
                -- continue
              elseif A.l + B.l > S then
                break
              else
                local a = A.m
                local b = B.m

                local logic = "{" .. A.s .. "({}())" .. B.s .. "}{}"
                local v = -res.value
                v = ((a + b + 1) * v * v + (a - b - 1) * v) // -2

                register_push(res.prefix .. "(" .. res.suffix .. ")", logic, v, res.pvalue + res.value)
                register_push(res.prefix, "(" .. res.suffix .. ")" .. logic, v + res.value, res.pvalue)
                register_push("", res.prefix .. "(" .. res.suffix .. ")" .. logic, v + res.value + res.pvalue, 0)
              end
            end
          end
        end
      end
    end
  end
  --]]

  -- addition
  -- [[
  if length >= 4 then
    for part1 = 4, length // 2, 2 do
      for _, res1 in get_pushes(part1) do
        for _, res2 in get_pushes(length - part1) do
          register_push(res2.prefix .. res1.prefix, res1.suffix .. res2.suffix, res1.value + res2.value, res1.pvalue + res2.pvalue)
        end
      end
    end
  end
  --]]

  -- pseudo-exponentiation (tehtmi)
  -- (n)<>(m){({}[()])<>(({}){})<>}{}<>{}
  -- (n)<>(m)                             -- push n and m on opposite stacks
  --         {                    }       -- sum and repeat
  --          ({}[()])                    -- top(m) - 1
  --                  <>(({}){})<>        -- n = 2*n; += n
  --                               {}     -- pop 0
  --                                 <>   -- swap to result
  --                                   {} -- pop and add n
  -- [[
  if length - 34 >= 4 then
    local subl = length - 34
    for part1 = 2, subl - 2, 2 do
      for _, res2 in get_pushes(part1) do
        local b = res2.value
        if b > 0 and b < 55 then -- overflow could be a problem, so bound...
          for _, res1 in get_pushes(subl - part1) do
            -- 2n + 4n + 8n + ... + (2^m)*n + 2^m * n
            -- n( 2 + 4 + 8 + .. 2^m + 2^m)
            -- n( 3 * 2^m - 2 )
            local a = res1.value
            local body = "(" .. res1.suffix .. ")<>" .. res2.prefix .. "(" .. res2.suffix .. "){({}[()])<>(({}){})<>}{}<>{}"
            local v = a * (3 * (1 << b) - 2) + b * (b - 1) // 2 + a + b + res2.pvalue
            register_push(res1.prefix, body, v, res1.pvalue)
            register_push("", res1.prefix .. body, v + res1.pvalue, 0)
          end
        end
      end
    end
  end
  --]]
end

--print(os.clock(), "seconds (startup)")

local start = os.clock()
for i = 2, k_max_len - 2, 2 do
  --print(i)
  process(i)
end

plen_cache = nil

local final = {}
for i = 1, k_limit do
  if pcache[i] ~= nil then
    final[i] = pcache[i].prefix .. "(" .. pcache[i].suffix .. ")"
  end
end

pcache = nil

-- hard coded to 10000 for ppcg test
local sieve = {}
for i = 1, 10000 do sieve[i] = true end
for i = 2, 10000 do
  for j = i * i, 10000, i do
    sieve[j] = false
  end
end

--print(os.clock() - start, "seconds (calculation)")

--local bf = require("execute2")

local count = 0
local sum = 0
local sum2 = 0
local maxlen = 0
local pcount = 0
for i = 1, k_limit do
  local res = final[i]
  final[i] = nil
  --print(i, #res, res)
  --local ev = res and bf.eval1(bf.compile(res)) or -1; assert( res == nil or ev == i, string.format("Failed %d %s %d", i, res or "", ev))
  if sieve[i] and i > 1000 then
    sum = #res + sum
    pcount = pcount + 1
  end
  if res then
    sum2 = #res + sum2
    maxlen = math.max(maxlen, #res)
    count = count + 1
  end
end
print("sum", sum)
--print("coverage", count / k_limit, "missing", k_limit - count)
--print("sum2", sum2)
--print("maxlen", maxlen)
assert(pcount == 1061)

Gagasan serupa dengan jawaban lain di mana fungsi bermanfaat yang diketahui digunakan untuk membangun angka yang lebih besar dari representasi angka sederhana yang bagus.

Satu perbedaan adalah bahwa alih-alih menyelesaikan masalah dalam jumlah yang lebih kecil, saya menyelesaikan masalah dalam jumlah dengan representasi yang lebih pendek. Saya pikir ini membuatnya lebih elegan untuk mengambil keuntungan dari angka negatif serta menangani kasus di mana angka yang lebih kecil diwakili dalam hal angka yang lebih besar.

Juga, mencoba untuk menemukan semua angka yang dapat direpresentasikan dalam ukuran tertentu daripada mencoba untuk mewakili angka tertentu sesegera mungkin sebenarnya menyederhanakan perhitungan tertentu. Alih-alih bekerja rumus secara terbalik untuk melihat apakah itu dapat diterapkan ke angka, rumus dapat bekerja ke depan dan diterapkan ke setiap angka.

Perbedaan lainnya adalah bahwa solusi yang diketahui disimpan dalam dua bagian - sebuah "awalan" (opsional) dan "akhiran" (lebih seperti infiks). Penilaian awalan diharapkan diabaikan ketika menghitung angka yang diberikan - awalan hanya berisi kode yang mengatur akhiran untuk dijalankan (umumnya dengan mendorong satu atau lebih hal ke stack). Jadi, diberi awalan dan akhiran, angka yang sesuai dapat didorong ke stack prefix(suffix).

Pemecahan ini pada dasarnya memecahkan masalah yang sama dengan unpackfungsi dalam jawaban Wheat Wizard. Alih-alih membungkus kode dengan <...>hanya untuk membatalkan ini nanti, kode tersebut hanya ditambahkan ke awalan.

Dalam beberapa kasus, awalan sebenarnya dievaluasi (terutama untuk operasi pseudo-eksponensial), sehingga penilaiannya juga disimpan. Namun, ini tidak benar-benar menyebabkan masalah besar, karena generator tidak mencoba membuat angka-angka tertentu. Tampaknya secara teoritis menyiratkan bahwa mungkin ada dua potong kode dengan panjang yang sama dan menghasilkan nomor yang sama yang tidak akan berlebihan dalam cache karena memiliki penilaian awalan yang berbeda. Saya tidak repot menghitung untuk ini, karena tampaknya tidak terlalu berarti (setidaknya dalam domain ini).

Saya membayangkan akan mudah mengurangi jumlah byte hanya dengan menambahkan lebih banyak case, tapi saya sudah cukup untuk saat ini.

Saya sudah lari ke 1000000, tetapi hanya melakukan kewarasan memeriksa hingga 100.000.

Pastebin output pada bilangan prima yang diberikan.

tehtmi
sumber
Apa yang harus k_limitdan k_max_lenlakukan? Saya tidak yakin saya mengerti judulnya.
Wheat Wizard
1
Daripada mencoba menghitung angka-angka tertentu, saya menghitung semua program yang berguna (yaitu memberikan jumlah yang tidak terlalu besar lebih pendek dari program lain yang ditemukan) hingga panjang tertentu - k_max_len. Itu bisa dengan mudah memeriksa bahwa ia telah menemukan semua angka yang Anda minta setelah memproses setiap panjang, tetapi itu berguna bagi saya untuk dapat mengikat panjang maks selama pengujian sehingga program akan berjalan lebih cepat. (Memproses panjang yang lebih besar bisa sangat lambat.) k_limitPada dasarnya adalah parameter input - itu akan menampilkan program untuk angka hingga ini - dengan asumsi k_max_lencukup besar untuk menemukannya.
tehtmi
4

ruby, 60246 byte

$brain_flak = Hash.new{|h, k|
    a = []
    a.push "()"*k
    if k > 1
        if k > 10
            # Triangle Numbers:
            n = (Math.sqrt(1+8*k).to_i-1)/2
            if (n*n+n)/2 == k
                a.push "("+h[n]+"){({}[()])}{}" 
                a.push  h[n+n]+")({({}[()])}{}"
            end
        end
        (k**0.51).to_i.downto(2){|i|
            # multiplication:
            if k%i==0
                a.push "("*(i-1) + h[k/i] + ")"*(i-1)+"{}"*(i-1)

            end
        }
        (k/2).downto(1){|i|
            # Addition
            a.push h[k-i] + h[i]
        }
    end

    h[k] = a.min_by{|x|x.length}
}
$brain_flak[0] = "<><>"

def get_code_for (i)
  "(#{$brain_flak[i]})"
end

Saya menggunakan hash. Saya menemukan golf terbaik untuk jumlah tertentu dan menggunakan yang lebih kecil untuk menemukan yang lebih besar.

Hash rekursif sangat menyenangkan!

MegaTom
sumber
2

Python, 64014 karakter

Saya tidak tahu apa-apa tentang brainflak sebelum tantangan ini dan hanya mengotak-atiknya sedikit di tryitonline, jadi mungkin ada jalan pintas yang jelas saya lewatkan. Ini adalah solusi yang cukup membosankan, hanya membagi input menjadi x=x/2+x%2atau x=x/3+x%3, mana yang lebih pendek.

k=lambda x:"(("+o(x/3)+")){}{}"+(x%3)*"()"if x>3else"()"*x
m=lambda x:"("+o(x/2)+"){}"+(x%2)*"()"if x>6else"()"*x
o=lambda x:min(k(x),m(x),key=len)
b=lambda x:"("+o(x)+")"

Sebut seperti ini: b(42)

output pada pastebin

KarlKastor
sumber
1

Lua, 64664 bytes

Program mencetak total panjang program dan program untuk prime ke-203 (ada garis yang dapat Anda ubah untuk mengubah mana yang dicetak, atau batalkan komentar pada garis untuk mencetak semua program)

Saat ini satu-satunya optimasi adalah x = 2 * n + 1

Mudah-mudahan saya akan punya waktu untuk menambahkan beberapa optimasi untuk menurunkan skor.

local primeS = [[<INSERT PRIMES HERE>]]

local primes = {}

for num in primeS:gmatch("%d+") do
    table.insert(primes, num+0)
end

local progs = {}
progs[0] = ""
progs[1] = "()"
progs[2] = "()()"

local function half(n)
    if progs[n] then return progs[n] end
    local p = ""
    local div = math.floor(n/2)
    local rem = n%2 == 1 and "()" or ""
    return "("..progs[div].."){}"..rem
end

for i = 3, 10000 do

    local bin = half(i)

    progs[i] = progs[i-1] .. "()"

    if #bin < #progs[i] then
        progs[i] = bin
    end

    if i % 1000 == 0 then
        print(i)
    end

end

local n = 203 -- This is the program it outputs
print(n..", ("..progs[203]..")")

local len = 0
for i,v in ipairs(primes) do
    len = len + #progs[v] + 2
    --print(v.." ("..progs[v]..")\n")
end
print("Total len: "..len)
PiGuy
sumber