간단한 역 폴란드 표기법 프로그래밍 언어를위한 컴파일러 최적화


24

기술

IPL (가상 프로그래밍 언어)은 폴란드어 역 표기법을 사용합니다. 다음과 같은 명령이 있습니다.

  • i- 숫자를 입력하고 스택으로 푸시
  • o- 스택의 비파괴 출력 상단 (번호는 스택에 유지됨)
  • d- 스택의 상단을 버린다
  • 정수 -이 숫자를 스택으로 푸시
  • +-* -스택에서 두 개의 숫자를 팝하고 해당 작업을 수행 한 후 결과를 되돌립니다. IPL에는 부서가 없습니다.

IPL은 정수로만 작동하며 간단한 계산에 사용됩니다. IPL 프로그램은 한 줄에 작성되며 공백으로 구분됩니다. 빈 문자열은 유효한 IPL 프로그램입니다.

IPL 프로그램 :

i i + o 

두 개의 숫자를 입력하고 함께 더한 결과를 출력합니다.

스택으로 푸시 할 수있는 입력 숫자와 정수는 [-999, 999] 범위에 있지만 출력은 어느 것이 든 가능합니다. 언어가 큰 숫자를 지원하지 않으면 괜찮습니다.

입출력 형식

문자열, 목록, 토큰 등 이해하고 읽고 쓸 수있는 한 입력 / 출력 형식을 선택할 수 있습니다.

태스크

일부 IPL 프로그램이 제공되며이를 최적화해야합니다 (길이 단축).

i 12 + 3 + o d 2 3 + d

최적화 후

i 15 + o

스택 상태를 보존 할 필요는 없지만 입력 및 출력량과 순서는 원본 및 최적화 된 프로그램과 일치해야합니다.

따라서 IPL 프로그램 :

-40 i * 2 * o i + 3 1 + o i 2 *

최적화 후

i -80 * o i 4 o i

또는

-80 i * o i 4 o i

(모든 입력은 관련이 없어도 저장해야합니다).

테스트 케이스에 대한 하드 코딩이 없어야하며, 코드는 임의의 IPL 프로그램에서 작동해야하며 요구 사항을 충족하는 가능한 가장 짧은 IPL 프로그램을 생성해야합니다.

채점

기본 코드 골프 스코어링.

업데이트 : @ Sanchises 제안에 따라 점수를 순수한 코드 골프 점수로 변경했습니다.

테스트 사례 :

입력:

(empty string)

가능한 출력 :

(empty string)

입력:

i 4 * 2 + 3 * 6 - o

가능한 출력 :

i 12 * o

입력:

1 1 + o

가능한 출력 :

2 o

입력:

i 2 + 3 + o d 2 3 + d

가능한 출력 :

i 5 + o

입력:

-40 i * 2 * o i + 3 1 + o i 2 *

가능한 출력 :

-80 i * o i 4 o i

입력:

i i 1 + i 1 + i 1 + i 1 + d d d d o 

가능한 출력 :

i i i i i d d d d o 

입력:

i i i 0 * * * o

가능한 출력 :

i i i 0 o

입력:

i i i 1 * * * o

가능한 출력 :

i i i * * o

입력:

i 222 + i 222 - + o

가능한 출력 :

i i + o

입력:

i 2 + 3 * 2 + 3 * 2 + 3 * i * d i 2 + 3 * i + d i o 2 + 2 - 0 * 1 o

가능한 출력 :

i i i i i o 1 o

입력:

i 1 + 2 * 1 + o 

가능한 출력 :

i 2 * 3 + o

입력:

1 1 + o i 2 + 3 + o d 2 3 + d 4 i * 2 * o i + 3 1 + o i 2 * i i 1 + i 1 + i 1 + i 1 + d d d d o i i i 0 * * * o i i i 1 * * * o i 2 + i 2 - + o i 2 + 3 * 2 + 3 * 2 + 3 * i * d i 2 + 3 * i + d i o 2 + 2 - 0 * 1 o

가능한 출력 :

2 o i 5 + o 8 i * o i 4 o i i i i i i d d d d o i i i 0 o i i i * * * o i i + o i i i i i o 1 o

1
질문 : 당신은 단순화 할 수 있습니다 i i d oi o i(입력 순서에 출력 순서에) 또는 당신이 그것을 간단하지 않겠습니까? (입력 출력 세트가 순서대로 있어야 함)
Sanchises

1
@Sanchises 아니오, 입력 및 출력이 순서대로 이루어져야합니다. 원래 프로그램이 출력하기 전에 2 개의 숫자를 입력하면 최적화 된 것이 동일하게 수행됩니다.
Андрей Ломакин

1
PPCG에 오신 것을 환영합니다! 좋은 첫 도전!
Luis felipe De jesus Munoz

6
에서 검토 큐 ,이 과제는 불분명하다 생각하지 않습니다. 그렇다면 왜 그런지 의견을 말하십시오.
mbomb007

2
@WW OP는 질문에 나열된 테스트 사례 만 하드 코딩해서는 안된다는 것을 의미한다고 생각합니다. 임의의 입력을 지원해야합니다. 테스트 케이스에는 하드 코딩이 없어야하며 코드는 임의의 IPL 프로그램에서
mbomb007

답변:


5

볼프람 언어 (티카) , 733 (728) 690 564 516 506 513 548 바이트

j=Integer;f=Flatten;s=SequenceReplace;A=FixedPoint[f@s[#,{{x_j,p,y_j,t}->{y,t,x*y,p},{x_j,y_j,p}->x+y,{x_j,y_j,t}->x*y,{x_j,p,y_j,p}->{x+y,p},{x_j,t,y_j,t}->{x*y,t},{0,p}|{1,t}->{},{0,t}->{d,0}}]//.{a___,Except[i|o]}->{a}&,#]&;B=Expand@Check[f@FoldPairList[f/@Switch[#2,i,{{i},{#,i@c++}},o,{{Last@#},#},d,{{},Most@#},p,{{},{#[[;;-3]],Tr@#[[-2;;]]}},t,{{},{#[[;;-3]],#[[-2]]*Last@#}},_,{{},{##}}]&,c=0;{},#],x]&;F=MinimalBy[w=A@f[#/.m->{-1,t,p}];z=B@w;s[#,{-1,t,p}->m]&/@A/@Select[Permutations@Join[w,Cases[z /.i@_->i,_j,∞]],B@#==z&],Length][[1]]&

온라인으로 사용해보십시오!

이것은 (1) "-"를 "-1 * +"로 대체하여 뺄셈을 처리 할 필요가없는 4 단계 둘러보기 (2) 명령 목록을 조금 단순화합니다 ( 3)이 명령 목록의 모든 순열 목록을 만들고 파싱 (실행) 할 때 동일한 결과를 제공하는 명령을 선택하고 (4) 특정 명령을 다시 변환 한 후 명령 목록을 조금 단순화하고 가장 짧은 명령 빼기.

이 코드는 입력 코드의 모든 순열 목록을 거치므로 매우 비효율적입니다. 긴 입력 코드의 경우이 코드를 실행하지 않는 것이 좋습니다. 그러나 그것을 읽으 면서이 도전에는 런타임 또는 메모리 제한이 없습니다.

이 코드는 모든 "-"연산을 부호가 뒤집힌 상태에서 "+"연산으로 변환 한 후 최적화 단계를 수행하며, 마지막으로 코드를 다시 문자열로 변환 할 때 "-"연산자를 다시 소개합니다. 이는 예를 들어 "i -1 i * + o"가 "ii-o"에 올바르게 최적화되었음을 의미합니다.

I / O 형식 요구 사항이 매우 느슨하기 때문에이 코드는 코드를 목록으로 가져 와서 반환합니다. 여기서 "+", "-", "*"기호는 각각 p, m, t, 토큰으로 표시됩니다. 문자열과의 변환은 TIO에 제공된 래퍼 함수에서 수행됩니다.

G[S_] := StringReplace[{"p" -> "+", "m" -> "-", "t" -> "*"}]@StringRiffle@
         Quiet@F@
         ToExpression[StringSplit[S] /. {"+" -> p, "-" -> m, "*" -> t}]

문자열 형식 래퍼를 포함하고 토큰 수 대신 최종 코드 문자열 길이를 최소화하고 몇 가지 변환 기능을 포함한 골프화되지 않은 버전 :

(* convert code string to list of operators *)
inputfilter[s_] := ToExpression[Flatten[StringSplit[s] /.
  {"i" -> i, "o" -> o, "d" -> d, "+" -> p, "-" -> {-1, t, p}, "*" -> t}]]

(* convert list of operators to code string *)
outputfilter[s_] := StringReplace[StringRiffle@Flatten@SequenceReplace[s,
  {{-1, t, p} -> m,                         (* convert "-1 t p" back to "-"             *)
   {x_ /; x < 0, p} -> {-x, m},             (* convert "y x +" to "y -x -" when x<0     *)
   {x_ /; x < 0, t, p} -> {-x, t, m}}],     (* convert "y x * +" to "y -x * -" when x<0 *)
  {"m" -> "-", "p" -> "+", "t" -> "*"}]     (* backsubstitution of symbols              *)

(* simplify a list of operators somewhat *)
simplifier[s_] := FixedPoint[Flatten@SequenceReplace[#,
  {{x_Integer, p, y_Integer, t} -> {y, t, x*y, p},  (*  "x + y *" -> "y * (xy) +"       *)
   {x_Integer, y_Integer, p} -> x + y,              (*  "x y +" -> "(x+y)"              *)
   {x_Integer, y_Integer, t} -> x*y,                (*  "x y *" -> "(xy)"               *)
   {x_Integer, p, y_Integer, p} -> {x + y, p},      (*  "x + y +" -> "(x+y) +"          *)
   {x_Integer, t, y_Integer, t} -> {x*y, t},        (*  "x * y *" -> "(xy) *            *)
   {0, p} | {1, t} -> {},                           (*  "0 +" and "1 *" are deleted     *)
   {x_Integer, i, p} -> {i, x, p},                  (*  "x i +" -> "i x +"              *)
   {x_Integer, i, t} -> {i, x, t},                  (*  "x i *" -> "i x *"              *)
   {0, t} -> {d, 0}}] //.                           (*  "0 *" -> "d 0"                  *)
  {a___, Except[i | o]} -> {a} &, s]                (* delete trailing useless code     *)

(* execute a list of operators and return the list of generated outputs *)
parse[s_] := Expand@Quiet@Check[Flatten@FoldPairList[  (* stack faults are caught here     *)
  Function[{stack, command},                        (* function called for every command*)
    Flatten /@ Switch[command,                      (* code interpretation:             *)
    i, {{i}, {stack, i[inputcounter++]}},           (* output "i" and add input to stack*)
    o, {{stack[[-1]]}, stack},                      (* output top of stack              *)
    d, {{}, Most[stack]},                           (* delete top of stack              *)
    p, {{}, {stack[[;; -3]], stack[[-2]] + stack[[-1]]}},  (* add two stack elements    *)
    t, {{}, {stack[[;; -3]], stack[[-2]]*stack[[-1]]}},    (* multiply two stack elements*)
    _, {{}, {stack, command}}]],                    (* put number onto stack            *)
    inputcounter = 0; {},                           (* start with zero input counter and empty stack*)
    s],                                             (* loop over code list              *)
  x]                                                (* return "x" if an error occurred  *)

(* the main function that takes a code string and returns an optimized code string *)
F[s_] := Module[{w, q},
  w = simplifier@inputfilter@s;      (* convert input to useful form *)
  q = parse[w];                      (* execute input code *)
  MinimalBy[
    outputfilter@*simplifier /@      (* simplify and stringify selected codes          *)
      Select[Permutations[w],        (* all permutations of code list                  *)
             parse[#] == q &],       (* select only those that give the correct output *)
    StringLength] // Union]          (* pick shortest solution by length               *)

버그 잡기를위한 @redundancy 덕분에 : 파서는 Expand분산 등가를 처리하기 위해 출력에 적용되어야합니다. 506 → 513

최신 정보

이제로 최적화 1 o 1 + o합니다 1 o 2 o. 이것은 놀랍게도 어려운 경우였으며 코드를 훨씬 느리게 만들었습니다. 513 → 548


테스트 케이스에 오류가있는 것 같습니다 i i 1 + i 1 + i 1 + i 1 + d d d d o.
그리미

@Grimy 내가 말했듯 이이 코드는 코드 공간을 철저하게 조합하여 검색하므로 큰 문제가 발생하지 않습니다. 귀하의 오류는 TIO의 메모리 부족 오류이며 내 코드가 아닙니다.
로마

"ii 1 + d o"에 대한 @Grimy 내 코드는 최적화 된 것으로 간주되는 "iid o"를 제공합니다. "ii 1 + i 1 + dd o"의 경우 "iii + d o"를 제공하는데, "iii + d o"는보다 명확한 "iiidd o"최적화와 동일한 수의 토큰을 갖습니다. 더 이상 입력을 시도하지 않았습니다.
로마

입력 i 2 * i 2 * + o이 최적화 된 출력을 생성해야 한다고 생각 i i + 2 * o하지만이 코드는 (최적화되지 않은) 입력을 반환합니다.
중복성

@ redundancy 덕분에 문제가 해결되었으며 이제 예제가 포함 된 테스트 사례 중 하나입니다.
로마
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.