Visualisator persamaan seni Ascii

10

Berurusan dengan persamaan tanpa adanya editor persamaan yang baik berantakan dan tidak menyenangkan. Misalnya, jika saya ingin mengekspresikan integral dan solusinya, mungkin akan terlihat seperti ini:

Integral [x ^ 3 e ^ (- mx ^ 2 b / 2), dx] = - ((2 + b m x ^ 2) / (b ^ 2 * e ^ ((b m x ^ 2) / 2) * m ^ 2))

Di integrals.wolfram.com , ini disebut "formulir input." Tidak ada yang suka melihat persamaan dalam "formulir input." Cara ideal untuk memvisualisasikan persamaan ini adalah:

masukkan deskripsi gambar di sini

(Wolfram menyebut ini "bentuk tradisional")

Untuk codegolf ini, tulis sebuah program yang akan mengambil beberapa persamaan dalam "bentuk input" sebagai input dan memvisualisasikan persamaan itu dalam representasi ascii dari "bentuk tradisional." Jadi, untuk contoh ini kita mungkin mendapatkan sesuatu seperti ini:

       /\      3
       |      x
       | ------------  dx = 
       |       2
      \/   (m x  b)/2
          e

              2
     2 + b m x
-(-----------------)
            2
   2  (b m x )/2  2
  b  e           m

Persyaratan:

  1. Jangan mengacak, menyederhanakan, atau mengatur ulang input dengan cara apa pun. Jadikan dalam bentuk yang persis sama seperti yang dijelaskan oleh input.
  2. Mendukung empat operasi matematika dasar (+, -, *, /). Ketika tidak mengalikan dua angka yang berdekatan, simbol * tersirat dan harus dihilangkan.
  3. Dukungan untuk integrasi (seperti yang ditunjukkan pada contoh di atas) tidak diperlukan. Mampu mendukung input dengan fungsi seperti Integrasi [...] atau Sqrt [...] adalah bonus.
  4. Mendukung kekuatan seperti yang ditunjukkan pada contoh di atas (akar ke-n dapat dimodelkan dengan menaikkan ke kekuatan ke-1).
  5. Kurung redundan (seperti yang ada di sekitar denomentator dan pembilang dari fraksi besar dalam contoh di atas) harus dihilangkan.
  6. Ekspresi dalam penyebut dan pembilang fraksi harus dipusatkan di atas dan di bawah garis pembagian horizontal.
  7. Anda dapat memilih untuk memulai baris baru atau tidak setelah tanda sama dengan. Pada contoh di atas, baris baru dimulai.
  8. Urutan operasi harus persis sama dengan output seperti pada input.

Beberapa contoh input dan output terkait untuk menguji solusi Anda:

Memasukkan:

1/2 + 1/3 + 1/4

Keluaran:

1   1   1
- + - + -
2   3   4

Memasukkan:

3x^2 / 2 + x^3^3

Keluaran:

   2     3
3 x     3
---- + x   
 2

Memasukkan:

(2 / x) / (5 / 4^2)

Keluaran:

2
-
x
--
5
--
 2
4

Memasukkan:

(3x^2)^(1/2)

Keluaran:

    2 1/2
(3 x )
Ami
sumber
Pertanyaan Anda umumnya harus memiliki tag yang menyatakan jenis kontesnya. Saya telah mengambil kebebasan untuk menambahkan satu karena Anda mengatakan "codegolf" dalam teks.
dmckee --- ex-moderator kitten
3
Masalah ini terlalu samar untuk menjadi kode-golf. Anda tidak mengatakan konstruksi apa yang harus didukung, atau seperti apa konstruksi itu. Apakah hanya mendukung +, -, *, dan / cukup? Apakah Sigma harus didukung? Bagaimana dengan huruf yunani? Solusi yang mungkin untuk pertanyaan seperti yang Anda ajukan itu bisa jadi terlalu beragam fungsinya untuk dibandingkan dengan panjang kode.
MtnViewMark
@ MtnViewMark, saya menambahkan beberapa "Persyaratan" ... beri tahu saya jika golf lebih baik sekarang.
Ami
@Mi - ya, banyak.
MtnViewMark
Saya setuju dengan MtnViewMark, ini tampaknya sangat terbuka dan tidak jelas. Mungkin Anda akan lebih baik untuk membatasi input dan output ke set testcases yang didefinisikan dengan baik untuk keperluan golf. Sudahkah Anda melakukan implementasi referensi?
gnibbler

Jawaban:

10

Python 2, 1666 karakter

Tata letak sebenarnya cukup mudah - itu adalah penguraian dari input yang menyakitkan kerajaan. Saya masih tidak yakin itu sepenuhnya benar.

import re,shlex
s=' '
R=range

# Tokenize.  The regex is because shlex doesn't treat 3x and x3 as two separate tokens.  The regex jams a space in between.                                                 
r=r'\1 \2'
f=re.sub
x=shlex.shlex(f('([^\d])(\d)',r,f('(\d)([^\d])',r,raw_input())))
T=[s]
while T[-1]:T+=[x.get_token()]
T[-1]=s

# convert implicit * to explicit *                                                                                                                                          
i=1
while T[i:]:
 if(T[i-1].isalnum()or T[i-1]in')]')and(T[i].isalnum()or T[i]in'('):T=T[:i]+['*']+T[i:]
 i+=1

# detect unary -, replace with !                                                                                                                                            
for i in R(len(T)):
 if T[i]=='-'and T[i-1]in'=+-*/^![( ':T[i]='!'
print T

# parse expression: returns tuple of op and args (if any)                                                                                                                   
B={'=':1,',':2,'+':3,'-':3,'*':4,'/':4,'^':5}
def P(t):
 d,m=0,9
 for i in R(len(t)):
  c=t[i];d+=c in'([';d-=c in')]'
  if d==0and c in B and(B[c]<m or m==B[c]and'^'!=c):m=B[c];r=(c,P(t[:i]),P(t[i+1:]))
 if m<9:return r
 if'!'==t[0]:return('!',P(t[1:]))
 if'('==t[0]:return P(t[1:-1])
 if'I'==t[0][0]:return('I',P(t[2:-1]))
 return(t[0],)

# parenthesize a layout                                                                                                                                                     
def S(x):
 A,a,b,c=x
 if b>1:A=['/'+A[0]+'\\']+['|'+A[i]+'|'for i in R(1,b-1)]+['\\'+A[-1]+'/']
 else:A=['('+A[0]+')']
 return[A,a+2,b,c]

# layout a parsed expression.  Returns array of strings (one for each line), width, height, centerline                                                                      
def L(z):
 p,g=z[0],map(L,z[1:])
 if p=='*':
  if z[1][0]in'+-':g[0]=S(g[0])
  if z[2][0]in'+-':g[1]=S(g[1])
 if p=='^'and z[1][0]in'+-*/^!':g[0]=S(g[0])
 if g:(A,a,b,c)=g[0]
 if g[1:]:(D,d,e,f)=g[1]
 if p in'-+*=,':
  C=max(c,f);E=max(b-c,e-f);F=C+E;U=[s+s+s]*F;U[C]=s+p+s;V=3
  if p in'*,':U=[s]*F;V=1
  return([x+u+y for x,u,y in zip((C-c)*[s*a]+A+(E-b+c)*[s*a],U,(C-f)*[s*d]+D+(E-e+f)*[s*d])],a+d+V,F,C)
 if'^'==p:return([s*a+x for x in D]+[x+s*d for x in A],a+d,b+e,c+e)
 if'/'==p:w=max(a,d);return([(w-a+1)/2*s+x+(w-a)/2*s for x in A]+['-'*w]+[(w-d+1)/2*s+x+(w-d)/2*s for x in D],w,b+e+1,b)
 if'!'==p:return([' -  '[i==c::2]+A[i]for i in R(b)],a+2,b,c)
 if'I'==p:h=max(3,b);A=(h-b)/2*[s*a]+A+(h-b+1)/2*[s*a];return(['  \\/|/\\  '[(i>0)+(i==h-1)::3]+A[i]for i in R(h)],a+3,h,h/2)
 return([p],len(p),1,0)

print'\n'.join(L(P(T[1:-1]))[0])

Untuk input besar dalam pertanyaan, saya mendapatkan:

 /\         2                     2 
 |     - m x  b          2 + b m x  
 |     --------    = - -------------
 |  3      2                    2   
\/ x  e         dx         b m x    
                           ------   
                        2     2    2
                       b  e       m 

Inilah beberapa kasus tes yang lebih rumit:

I:(2^3)^4
O:    4
  / 3\ 
  \2 / 

I:(2(3+4)5)^6
O:             6
  (2 (3 + 4) 5) 

I:x Integral[x^2,dx] y
O:   /\ 2     
  x  | x  dx y
    \/        

I:(-x)^y
O:     y
  (- x) 

I:-x^y
O:     y
  (- x)

Yang terakhir salah, beberapa kesalahan diutamakan di parser.

Keith Randall
sumber
bukankah seharusnya dasar argumen integral terpusat secara vertikal setelah integral? Saat ini lebih mirip subscript ke integral.
Joey
Tidak sulit untuk berubah, tetapi itu akan membuang-buang ruang. Saat ini saya membuat tanda integral cukup besar untuk merentangkan argumennya (dengan 3 minimum tinggi).
Keith Randall
Golf ringan: Gunakan tab alih-alih spasi ganda.
CalculatorFeline