Ascii Kunstgleichungsvisualisierer

10

Der Umgang mit Gleichungen ohne einen guten Gleichungseditor ist chaotisch und unangenehm. Wenn ich zum Beispiel ein Integral und seine Lösung ausdrücken wollte, könnte es ungefähr so ​​aussehen:

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

Bei integrals.wolfram.com wird dies als "Eingabeformular" bezeichnet. Niemand mag es, eine Gleichung in "Eingabeform" zu sehen. Die ideale Art, diese Gleichung zu visualisieren, wäre:

Geben Sie hier die Bildbeschreibung ein

(Wolfram nennt diese "traditionelle Form")

Schreiben Sie für diesen Codegolf ein Programm, das eine Gleichung in "Eingabeform" als Eingabe verwendet und diese Gleichung in einer ASCII-Darstellung der "traditionellen Form" visualisiert. Für dieses Beispiel könnten wir also so etwas bekommen:

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

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

Bedarf:

  1. Mischen, vereinfachen oder ordnen Sie die Eingabe in keiner Weise neu. Rendern Sie es in genau der Form, in der es von der Eingabe beschrieben wurde.
  2. Unterstützen Sie die vier grundlegenden mathematischen Operationen (+, -, *, /). Wenn zwei benachbarte Zahlen nicht multipliziert werden, ist das Symbol * impliziert und sollte weggelassen werden.
  3. Unterstützung für die Integration (wie im obigen Beispiel gezeigt) ist nicht erforderlich. Die Unterstützung von Eingaben mit Funktionen wie [...] Integrieren oder [...] Sqrt ist ein Bonus.
  4. Unterstützungskräfte wie im obigen Beispiel gezeigt (die n-te Wurzel kann durch Erhöhen auf die 1 / n-te Kraft modelliert werden).
  5. Redundante Klammern (wie die um den Denomentator und den Zähler des großen Bruchteils im obigen Beispiel) sollten weggelassen werden.
  6. Der Ausdruck im Nenner und Zähler eines Bruchs sollte über und unter der horizontalen Trennlinie zentriert sein.
  7. Sie können wählen, ob nach einem Gleichheitszeichen eine neue Zeile beginnen soll oder nicht. Im obigen Beispiel wird eine neue Zeile gestartet.
  8. Die Reihenfolge der Operationen muss in der Ausgabe genau dieselbe sein wie in der Eingabe.

Einige Beispiele für Eingaben und zugehörige Ausgaben zum Testen Ihrer Lösung:

Eingang:

1/2 + 1/3 + 1/4

Ausgabe:

1   1   1
- + - + -
2   3   4

Eingang:

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

Ausgabe:

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

Eingang:

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

Ausgabe:

2
-
x
--
5
--
 2
4

Eingang:

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

Ausgabe:

    2 1/2
(3 x )
Ami
quelle
Ihre Frage sollte im Allgemeinen mit einem Tag versehen sein, der angibt, um welche Art von Wettbewerb es sich handelt. Ich habe mir erlaubt, einen hinzuzufügen, weil Sie im Text "Codegolf" gesagt haben.
dmckee --- Ex-Moderator Kätzchen
3
Dieses Problem ist zu nebulös, um Code-Golf zu spielen. Sie sagen nicht, welche Konstrukte unterstützt werden müssen oder wie sie aussehen müssen. Würde es ausreichen, nur +, -, * und / zu unterstützen? Muss Sigma unterstützt werden? Was ist mit griechischen Buchstaben? Die möglichen Lösungen für die von Ihnen gestellte Frage sind möglicherweise zu unterschiedlich in der Funktionalität, um mit der Codelänge verglichen zu werden.
MtnViewMark
@MtnViewMark, ich habe einige "Anforderungen" hinzugefügt ... lassen Sie mich wissen, ob der Golf jetzt besser ist.
Ami
@ Ami - ja, viel.
MtnViewMark
Ich stimme MtnViewMark zu, dies scheint sehr offen und vage zu sein. Vielleicht ist es besser, die Eingabe und Ausgabe auf eine genau definierte Reihe von Testfällen zu beschränken, um Golf zu spielen. Haben Sie eine Referenzimplementierung durchgeführt?
Gnibbler

Antworten:

10

Python 2, 1666 Zeichen

Das Layout ist eigentlich ziemlich einfach - es ist das Parsen der Eingabe, das ein königlicher Schmerz ist. Ich bin mir immer noch nicht sicher, ob es völlig richtig ist.

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

Für den großen Input in der Frage bekomme ich:

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

Hier sind einige weitere knifflige Testfälle:

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)

Letzteres ist falsch, ein Vorrangfehler im Parser.

Keith Randall
quelle
Sollte die Grundlinie des Integralarguments nicht nach dem Integral verisch zentriert sein? Derzeit sieht es eher wie ein Index für das Integral aus.
Joey
Nicht schwer zu ändern, aber es würde etwas Platz verschwenden. Ich mache derzeit das Integralzeichen gerade groß genug, um sein Argument zu überspannen (mit einem Minimum von 3 hoch).
Keith Randall
Leichtes Golfspiel: Verwenden Sie Tabulatoren anstelle von doppelten Leerzeichen.
CalculatorFeline