Гольф Мозговий Флак Цілий


28

Цілі особи нудно представляти в « Брейн-Флак» . Є 8 операторів:

()      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

fooможе складатися з декількох операторів, і в цьому випадку вони оцінюються та підсумовуються. Наприклад, (()())натискає 2на стек (і оцінює 2також).

Очевидно, що (()...())механізм не корисний у Code Golf, оскільки велика кількість займає n*2+2байти. Таким чином, ваше завдання полягає в тому, щоб написати програму або функцію, яка видасть якомога менше байтів програму Brain-Flak, яка підштовхне задане ціле число nдо активного стеку. Ця програма не повинна робити жодних припущень щодо наявного вмісту стеків, тому вона не повинна залишати обмінювані стеки або додавати або видаляти зайві значення зі стеків.

Хоча ваша програма або функція повинна бути здатна повернути працюючу програму Brain-Flak на всі входи від 1 до 1 000 000, переможцем стане програма або функція, яка генерує найменший набір відповідних програм Brain-Flak для всіх 1061 простих чисел між 1000 і 10 000 . Ви повинні відзначити загальний розмір ваших результатів для цих 1061 входів як частини вашої подачі. Ваша програма або функція може прийняти ціле число і повернути (рядок) програму Brain-Flak у будь-якому звичайному прийнятному форматі вводу / виводу. Зв'язки будуть порушені з використанням розміру вашої програми чи функції.


4
Як зауваження: кількість дійсних програм довжини 2nстановить 4^n catalan(n).
Leaky Nun

2
Хм, мені подобається виклик, але я думаю, що його слід оцінювати за невідомими цілими числами. В іншому випадку, цілі програми, зафіксовані, можуть бути жорстокими, а інші цілі числа просто залишені як (()()()...()). Плюс, якщо ви просто використовуєте прості числа, це може пропустити деякі оптимізації для композитів.
DJMcMayhem

Крім того, чому не []визначено для цього завдання? Мені дивно реалізувати 7 з 8 операторів. У будь-якому випадку, класний виклик, мені чесно, що хтось напише виклик, натхненний моєю рідною мовою!
DJMcMayhem

2
@DJMcMayhem Я хочу, щоб люди могли обчислити свій власний бал. Усі відповідні прості числа - це більше, ніж складене число, тому потенційних оптимізацій повинно бути багато. Крім того, я не хочу, щоб люди покладалися на певну цінність []у своїй відповіді.
Ніл

1
@YetiCGN Розмір сценарію вважається лише перемикачем.
Ніл

Відповіді:


16

Пітон 2, 59394 59244 58534 58416 58394 58250

Добре ось моє рішення.

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

Відповідна функція є push(n). Щоб викликати це, просто натисніть на ціле число, яке ви хочете представити.

Пояснення

Основна оптимізація, здійснена програмою, - це жорстке кодування множення. Ідея жорсткого кодування множення досить проста. Ви натискаєте число, а потім вискакуєте і натискаєте його, щоб створити нове значення. Наприклад, для множення на два ви можете використовувати наступний код, ((n){})де n код, що створює певне число. Це працює тому, що обидва (n)і {}мають значення n.

Цю просту ідею можна зробити більш складною для більшої кількості. Візьмемо для прикладу 5. Нещодавно було виявлено, що найкращим способом множення на п'ять було (((n)){}){}{}. Цей код робить дві копії з n множиться одна на 4 і додає дві. Використовуючи ту саму стратегію, я роблю кожне множення на основі двійкового подання числа. Я не буду вникати в деталі, як це працює зараз, але я це роблю, відрізаючи перше бінарне представлення та замінюючи 0 на ){}та 1 на){}{}. Потім він гарантує, що n буде натиснуто відповідну кількість разів і збалансує всі круглі дужки. (Якщо ви хочете знати, як це робиться, ви можете подивитися на мій код). Якщо ви хочете знати, чому це працює, просто запитайте мене в коментарі. Я не думаю, що ніхто насправді не читає всі оновлення моєї публікації, тому я не залишив пояснення.

Коли алгоритм намагається знайти жорсткий код множення, він намагається просте численні фактори. Він ігнорує складені фактори, оскільки в один момент композиційні чинники завжди можуть бути виражені більш стисло, як власні основні фактори, невідомо, чи це все-таки вірно.

Інший механізм збереження байтів - це пошук многочлену. Існують певні форми многочленів, які легко зобразити за допомогою петель, що зменшуються. Ці многочлени включають, але не обмежуються ними, багатокутні числа. Ця оптимізація знаходить многочлени, які відповідають формі і створює код, який їх складає.

Вихідні дані

паштет


"чи n більший, чи менший, ніж n + 1" ??
Спарр

@Sparr, чи інтерпретація nбільша чи менша, ніжn+1
Пшеничний майстер

Вам слід від'єднати рядки від if n % 3 == 2: кінця цієї функції на одному рівні.
користувач202729

13

Мозг-Флак, 64664

Спробуйте в Інтернеті!

Ось мій анотований код

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

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

Пояснення

Наразі це реалізує лише два правила:

  • Якщо n ділиться на два повернення (n/2){}

  • Якщо n не ділиться на два повернення n-1()

Він також твердо кодує всі числа менше 6.


Схоже, перевірка на подільність на три має зменшити бал на трохи
лише ASCII

@ ASCII-тільки я насправді реалізував це, і це збільшило кількість байтів. Я працюю над способом впровадження розумнішої версії поділу на три.
Пшеничний майстер

Гаразд, використовуючи Brain-Flak для створення програми, яка генерує числа Brain-Frak. Приємно.
Draco18s

10

Perl, 59222 59156 58460 символів

  • n() (11322660 символів)
  • (n){}() (64664 символів)
  • ((n)){}{} (63610 символів)
  • ((n)()){}{} (63484 символів) - це нове підрахунок
  • (n){({}[()])}{} (60748 символів)
  • n[m] (62800 символів)
  • (n){m({}[l])}{} (58460 символів) - це нове підрахунок

Формула для останнього розрахунку така n(n/l+1)/2+mn/l. Я спробував деякі інші розрахунки, але вони більше не корисні для даного результату. Програма фактично генерує всі значення до 9999, але потім перераховує задані прості числа та їх загальну довжину.

@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);
}

Чи можете ви надати посилання на вихід?
DJMcMayhem

@DJMcMayhem На жаль, я випадково пошкодив свій список простих чисел, визнавши недійсним кількість персонажів.
Ніл

@Linus ((X) ()) {} {} натискає на X, потім додає 1, виштовхує результат, потім з'являється X + 1 і X. Всього 3X + 2. Я думаю, що я спробував іншу формулу на Try It Online, але я можу перевірити ще раз, якщо вам подобається.
Ніл

@Neil Моя помилка ... Вони виглядають добре, але що саме псує ваші праймери тоді?
Лінус

1
@Neil Я отримую 58158, коли я додаю &try($i * $i, "$numbers[$i]{({})({}[()])}{}");, що знижується до 58032, коли я також додаю &try((3 * $i * $i - $i) / 2, "$numbers[$i]{({})({}[()])({})}{}");(квадратні / п’ятикутні числа) - це звідси
ASCII-тільки

5

Пітон, 59136 58676 символів

Функція гольфу з номером 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])

Ітерація простих номерів:

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)

Вихід:

Пастебін

Пояснення:

Ми попередньо заповнюємо список R представлення брейн-лук, оцінюючи окремі цілі числа в більшому, ніж необхідному, діапазоні [1, m -1], щоб визначити нашу функцію f . Представлення формуються шляхом взяття найнижчого невикористаного подання (індексується l ) та формування з нього багатьох нових уявлень, зберігаючи лише найкоротші. Найменше невикористане представлення передбачає, що всім числом 1 до l було призначено подання, і що ці представлення вже використовувались для отримання нових чисел. Якщо значення менше l отримує коротше подання, ми повинні повернутися назад і відтворити числа, починаючи з цієї точки. Функція f виробляє програму збереження числа до стека, додаючи дужки.

Коли я починав це, я не знав жодного Брейнфлака, і дуже вдячний відповіді Еймона Оліва за вказівку формули для трикутних чисел. Здебільшого я узагальнив підсумки і невпинно ставився до перевірки сум та різниць. Додавання великої кількості кратних сум дало великий ефект.

Для тих, хто хвилює, ось код скретча, який я використовував, щоб побачити, які формули того варті.

Формули представництва:

  1. Множення на малі прости:
    (X){}
    ((X)){}{}
    ((((X)))){}{}{}{}
    ((((((X)))))){}{}{}{}{}{}
  2. Додавання X + Y :
    XY
  3. Віднімання X - Y :
    X[Y]
  4. Підсумовування та включення X приросту Y :
    (X){({}[Y])}{}
  5. Кратні складання в X збільшення Y , а також X : і
    (X)({({}[Y])}{}){}
    (X)(({({}[Y])}{})){}{}
    (X)(({({}[Y])}{}){}){}
    т.д. ...

Я подумав, що 5 * не допомагає, але тепер я бачу, що це зекономить 10 моїх відповідей. Я думав, що спробував ці підсумки, але я ще раз перевірю!
Ніл

Підсумки приросту плюс кратні заощаджують мені ще 46 байт, і навіть тоді мені доведеться тричі промити і повторити, щоб упіймати їх усіх.
Ніл

Виявляється, якщо я використовую віднімання, я більше не використовую 5 *.
Ніл

4

Луа 5.3, 57522

Я фактично почав працювати над цією спиною, коли було опубліковано питання, але забув про це до ювілею 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)

Аналогічна ідея з іншими відповідями, де відомі корисні функції використовуються для створення більших чисел із хороших уявлень простіших чисел.

Одна відмінність полягає в тому, що замість того, щоб розв'язувати підпрограми у вигляді менших чисел, я розв'язую підпрограми в термінах чисел із більш короткими поданнями. Я думаю, що це робить більш елегантним використовувати переваги від’ємних чисел, а також обробляти випадок, коли менші числа представлені у вигляді більших чисел.

Крім того, спроба знайти всі числа, які можуть бути представлені певного розміру, а не намагатися представити певне число якомога коротше, фактично спрощує певні обчислення. Замість того, щоб формула працювала зворотно, щоб побачити, чи можна її застосувати до числа, формулу можна працювати вперед і застосовувати до кожного числа.

Ще одна відмінність полягає в тому, що відомі рішення зберігаються у двох частинах - (необов’язково) «префікс» та «суфікс» (більше схожий на інфікс). Очікується, що оцінка префікса буде ігнорована при обчисленні заданого числа - префікс просто містить код, який встановлює суфікс для запуску (як правило, натисканням однієї або декількох речей до стеку). Отже, з урахуванням префікса та суфікса, відповідне число можна натиснути на стек за допомогою prefix(suffix).

Цей розкол в основному вирішує ту саму проблему, що і unpackфункція у відповіді Майстра пшениці. Замість того, щоб обгортати код <...>лише з тим, щоб скасувати це пізніше, такий код просто додається до префікса.

У кількох випадках префікс насправді оцінюється (головним чином для операції псевдоекспоненції), тому його оцінка також зберігається. Однак це насправді не викликає великих проблем, оскільки генератор не намагається побудувати конкретні числа. Здається, теоретично випливає, що може бути два фрагменти коду однакової довжини і генерувати однакове число, яке не було б зайвим у кеші через різні оцінки префікса. Я не турбувався обліку цього, хоча це, мабуть, не має великого значення (принаймні, у цій галузі).

Я думаю, було б легко знизити кількість байтів, додавши більше справ, але на даний момент у мене було достатньо.

Я пробіг до 1000000, але робив лише перевірку розумності до 100000.

Вставлення виводу на задані праймери.


Що робити k_limitі k_max_lenробити? Я не впевнений, що розумію заголовок.
Пшеничний майстер

1
Замість того, щоб намагатися обчислити певні числа, я обчислюю всі корисні (тобто даю не надто великі числа коротші, ніж будь-яка інша знайдена програма) програм до певної довжини - k_max_len. Це може так само легко перевірити, що він знайшов усі числа, про які ви просили після обробки кожної довжини, але мені було корисно, щоб я міг обмежувати максимальну довжину під час тестування, щоб програма працювала швидше. (Обробка більшої довжини може бути дуже повільною.) k_limitВ основному вхідний параметр - він буде виводити програми для чисел до цього - якщо припустити, що вони k_max_lenбули досить великими, щоб їх знайти.
tehtmi

4

рубін, 60246 байт

$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

Я використовую хеш. Я знаходжу найкращий гольф для заданої кількості і використовую менші, щоб знайти більші.

Рекурсивні хеші - це так весело!


2

Пітон, 64014 символів

До цього виклику я нічого не знав про brainflak, і лише трохи поспілкувався з ним на трийтонеліні, тож я міг пропустити явні ярлики. Це досить нудне рішення, воно просто розбиває вхід на x=x/2+x%2або x=x/3+x%3, в залежності від того, що коротше.

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)+")"

Назвіть це так: b(42)

вихід на пастебін


1

Луа, 64664 байт

Програма друкує загальну тривалість програм і програми для 203-го простого (там рядок, який ви можете змінити, щоб змінити, який з них надруковано, або відмітити рядок для друку всіх програм)

Зараз єдиною оптимізацією є x = 2 * n + 1

Сподіваюся, я встигну додати ще кілька оптимізацій для зниження балів.

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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.