8
\$\begingroup\$

Thank you guys so much for your help with calculus. Now I need some help with my upcoming trigonometry test.

On the test, I'll need to simplify expressions. I’ll be given input like 4sin(x)/(2cos(x)) and will have to produce a simpler, but equivalent expression (such as 2tan(x)). All angles are in degrees, and we'll pretend there are no division-by-zero or invalid-domain issues. (For example, we'll assume that tan(x+1)cot(x+1)sin(x)/sin(x) is always 1.)

I snuck into the professor's office, and got a list of 100 problems that might be on the test. Please give me teh code to solve them all. It’s possible that some of the problems are already simplified as much as possible; if so just give back the input.

I need expressions to be simplified, but I also want a short program (or function) so the professor won't notice. Try to minimize the sum of the program’s length and the total length of all of the solutions.

Just to clarify, it's okay if some of the expressions are returned unchanged, or even returned in an equivalent but longer form. Also, the program only needs to work on the expressions listed below; it can return incorrect results or even break for other inputs.

As you can tell, all of the problems follow a similar format. x is the only variable used, there are no spaces, and parentheses follow each function name. (The functions are sin, cos, tan, sec, csc, and tan.) There are no nested functions, but inside a function may be an expression like 3x+4.5 or -2-.7x. Exponents may be used, but only on functions (e.g. sin(x-.5)^7), and the power is always a integer above one. Multiplication is indicated through concatenation.

The outputs will need to be in this format as well. Invalid: sin x, sin(x)/cos(x)tan(x) [is the tangent multiplied or divided?], cos(x [close all parentheses], 4*sin(x), sec(x)^1

I can use any programming language, unless it relies on built-in simplification or expression-handling functions. Built-in trig functions are okay. (I'll have a very basic scientific calculator during the test.) Also, since I'll be reading the program written on paper, I can only use printable ASCII characters (0x20 through 0x7E) and newlines.

1/(sec(x))
4+sin(x)+3
(cos(7x+4)-sin(-3x))/(sin(-3x))
2sin(x)2tan(x).25cos(x)^3cos(x)+1+1
7cos(x)sec(x)/(14tan(x)csc(x))
sin(x)cos(x)/sec(x)
8sin(x)cos(x)sin(x)/tan(x)+8sin(x)
sin(x)^9cos(x)cot(x)sec(x)csc(x)sec(x)tan(x)/(cot(x)^2tan(x)cos(x)^4cot(x)sin(x))
tan(x)cos(x)csc(x)
tan(x+1)sin(x-1)cos(x+1)^3tan(x-1)^2sin(-x+1)csc(x+1)tan(-x+1)/(cos(x-1)cot(x+1))
(cos(2x)+cot(2x)-sin(2x)+csc(2x)^3)/(cot(2x)+sin(2x))
cos(90-x)cos(x)
sin(x+180)sec(450-x)
tan(-x)sin(x+90)sec(x-90)
tan(x+180)^2
cot(-x)cos(-x)
cot(180-x)^3cos(270-x)^2
sin(.1x-.2)sin(.1x-.2)sin(.1x-.2)sin(.2-.1x)sin(.2-.1x)
sin(x)
sin(90-x)sin(x)+cos(90-x)/sec(x)
tan(3x+2)cos(3x+2)/sin(3x+2)-1
cos(x)cos(x)cos(x)cos(x)cos(x)
sec(2x+1)sec(-1-2x)+sec(-2x-1)sec(2x+1)
cos(4x)cot(4x)tan(4x)sin(4x)csc(4x)
-cos(x)+cos(x)+sin(2x-4)-1/csc(2x-4)
sec(x)sec(x+2)cot(x)tan(x-2)tan(x+180)
tan(x)(tan(x))
3sin(x)sin(x)/(3)
cos(x)sin(x)
tan(x)sec(x)^2
tan(x)^2-sec(x)^2
7+sin(x)csc(x)csc(x)+cot(x)^2
sin(90)+cos(-90)+sec(180)
csc(1)+csc(10)-csc(30)-csc(60)+csc(90)
sin(36000001)
csc(800)+(cot(720+x)-sec(4x-720))
sin(-x)+sin(x)
csc(-x)+csc(x)
4sin(x)-sin(x)+tan(x)-2tan(x)
cot(x)+10cot(x+90)+99cot(x+180)+.01cot(x-90)
tan(x)tan(x+180)
sec(x)sin(x+180)tan(x-270)cot(x-450)csc(x+90)
sin(x)/cot(x)+sin(x)/cot(x)
sin(x)csc(x)+tan(x)cot(x)+cos(x)sec(x)
cot(x)
9tan(x+90)+90tan(x+9)
cos(x-9999)+tan(x+99999)
2tan(x)tan(x)/2
tan(x)/tan(x-360)+cos(x+180)/cos(x)
csc(4x)sec(270-4x)
cot(91+x)tan(x-449)
csc(2x)(csc(2x)-sin(2x))
csc(x+1)^2-cot(x+1)cot(x+1)
cot(x)cot(x)+1
tan(x)^2-sec(x)sec(x)
tan(x)/cot(x)+csc(x)/csc(x)
cot(x)sin(x)/cos(x)
csc(x)tan(x)cos(x)
csc(x)cot(x)cos(x)
csc(x+90)csc(-x+270)-1
cot(x)/cot(x)+tan(x)/cot(x)+cot(x)cot(x)
sec(x)sec(x)sec(x)sec(x+90)sec(x-90)sec(x+180)
1-cos(x)cos(x+180)+sin(x)^2
sec(x)sec(x)sec(x)sec(x)/cos(x)+cot(x)
cot(x+1)csc(x-1)sec(x+1)tan(x-1)sin(x+1)cos(x-1)
sin(x)-cos(x)+tan(x)-sec(x)+cos(x)-csc(x)
tan(x+23515)-sec(-.27x-23456)
sec(-.9x)
-tan(-x)-csc(360-x)
cos(-x)sec(x)sin(x)csc(-x)
tan(-x)^2-sin(-x)/sin(x)
tan(x)tan(x)+1
csc(x)^2-1
cot(2x)cot(2x)-csc(2x)/sin(2x)
2sec(x)/(6cos(x))
sec(0)+tan(30)cos(60)-csc(90)sin(120)cot(150)+tan(180)csc(210)sin(240)-cos(270)sec(300)+cot(330)
tan(x-1234567)sec(4781053+x)^2
tan(-1234567x)sec(4781053x)^2
sin(x)^9+cos(x)^7+csc(x)^5-cot(x)^3
cos(-33x-7.7)
sec(-.1-x)+tan(-2x-77)
tan(x)+sin(x)-cos(x)+tan(x)-sin(x)
cos(x)-sec(x)/tan(x)+tan(x)/sin(x)
cot(x)-cos(x)/sin(x)
3cos(x)+2/sec(x)-10sin(x)/(2tan(x))
tan(x+3)^11+sin(x+3)^8-cos(x+3)^5+5
sec(x)+sec(x)
csc(.1x)csc(-.1x)csc(x)
cot(x-7)cot(x-7)cot(x+173)cot(x-7)cot(x+173)cot(x-367)
cos(.0001x+1234567)
cot(45)+tan(225)-sin(210)+cos(-60)
sin(12345)cos(23456)tan(34567)sec(45678)csc(56789)cot(67890)
cos(1234x)+cot(1234)+tan(1234x)+sec(1234)+csc(1234)+sin(1234x)
sec(x)sec(x)sec(x)sec(x)sec(x)sec(x)
csc(x)cot(x)sec(x)csc(x)tan(x)sec(x)cot(x)csc(x)cot(x)cos(x)cos(x)cot(x)sin(x)sin(x)cot(x)
csc(2553273)+cot(1507348)-sec(5518930)+csc(5215523)+tan(3471985)-sec(4985147)
sin(20x)+cos(20x)-tan(20x)+sin(20x)-csc(20x)+cot(20x)-tan(20x)+csc(20x)
cot(100000)+cot(100000x)+cot(100000x)+cot(100000)
csc(5x+777)sin(5x+777)
csc(4.5x)

Note: This scenario is entirely fictional. In real life, cheating and helping others cheat is wrong and should never be done.

\$\endgroup\$
  • 5
    \$\begingroup\$ I count no less than forty different identities and mathematical axioms that would be needed to simplify this. Even parsing one of the expressions and getting it into some kind of structured internal form would take a fair bit of code. Too rich for me. But maybe there are some here looking for this kind of a challenge. \$\endgroup\$ – COTO Sep 30 '14 at 4:23
  • \$\begingroup\$ @COTO you don't have to parse it. You can try to detect which problem it as and hardcode the answers in compressed form. It might even be shorter than parsing. \$\endgroup\$ – Ingo Bürk Sep 30 '14 at 4:51
  • 3
    \$\begingroup\$ if your printer cannot print any non-ASCII character, you need a better printer. \$\endgroup\$ – John Dvorak Sep 30 '14 at 6:56
  • 3
    \$\begingroup\$ I just thougth WTF this guy even got UPVOTES? Then I noticed that it wasn't math.SE, soo... context matters=) \$\endgroup\$ – flawr Sep 30 '14 at 13:14
  • 1
    \$\begingroup\$ @Ypnypn Oh, ok, so for example we can't reduce sin(36000001) to .017452 \$\endgroup\$ – Digital Trauma Sep 30 '14 at 18:30
8
\$\begingroup\$

Python, 436 + 1909 = 2345

This must be one of the most inefficient solutions imaginable and mathematicians will probably cringe, but I've managed to throw something together that actually simplifies about half of the expressions without any hardcoding:

from math import*
import exrex,re
d=lambda f:lambda x:f(x*pi/180)
sin,cos,tan=d(sin),d(cos),d(tan)
i=lambda f:lambda x:1/f(x)
sec,csc,cot=i(cos),i(sin),i(tan)
t=lambda s:[round(eval(re.sub('([\d\).])([\(a-z])','\\1*\\2',s).replace('^','**')+'+0')*1e9)for x in[1,44]]
def f(I):
 try:return min((s for s in exrex.generate('(-?\d|\(1/\d\.\))?([+-]?(sin|cos|tan|cot|sec|csc)\(x\)(\^\d)?){0,4}')if s and t(s)==t(I)),key=len)
 except:return I

The output for the 100 test cases should be the following (where # marks expressions that were not simplified):

cos(x)
7+sin(x)
#
2+tan(x)^2cos(x)^2
(1/2.)cos(x)
sin(x)cos(x)^2
#
sin(x)^2tan(x)^7
1
#
#
sin(x)cos(x)
-1
-1
tan(x)^2
-cot(x)cos(x)
-cot(x)cos(x)^2
#
sin(x)
2sin(x)cos(x)
0
cos(x)^5
#
#
#
#
tan(x)^2
sin(x)^2
sin(x)cos(x)
tan(x)sec(x)^2
-1
7+cot(x)^2+csc(x)
0
#
#
#
0
0
3sin(x)-tan(x)
#
tan(x)^2
-tan(x)sec(x)
2sin(x)tan(x)
3
cot(x)
#
#
tan(x)^2
0
#
1
#
1
csc(x)^2
-1
sec(x)^2
1
1
cot(x)^2
-1-sec(x)^2
cot(x)^2+sec(x)^2
sec(x)^4csc(x)^2
2
cot(x)+sec(x)^5
#
sin(x)+tan(x)-csc(x)-sec(x)
#
#
tan(x)+csc(x)
-1
sec(x)^2
sec(x)^2
cot(x)^2
-1
(1/3.)sec(x)^2
#
#
#
#
#
#
2tan(x)-cos(x)
cos(x)-csc(x)+sec(x)
0
0
#
2sec(x)
#
#
#
3
#
#
sec(x)^6
cot(x)^4csc(x)
#
#
#
1
#

The idea is quite simple:

  • generate a huge amount of possible expressions
  • select those that yield the same result as the expression you want to simplify, comparing them for some (here two) x values
  • from the equivalent expressions return the shortest one

The problem is that there are quite a lot of possible expressions to check, so I limited it to a subset.

To be honest I was not patient enough to test the golfed code above. (Tell me if you think that's cheating.) Instead I used a much longer but more efficient rule to generate an even smaller subset of expressions that hopefully still contains all the desired simplifications. Should you want to try that, replace the regular expression in the second to last line of the code with the following (and be prepared for a few minutes of computation time):

'0|((-1|\(1/[23]\.\)|[1237])[+-]?)?(sin\(x\)(\^2)?)?-?(tan\(x\)(\^[27])?)?(cot\(x\)(\^[24])?)?[+-]?(cos\(x\)(\^[25])?)?(sec\(x\)(\^[2456])?)?(csc\(x\)(\^2)?)?'

The program also contains quite some overhead that was needed to make Python understand the mathematical expressions. This involved

  • redefining sin,cosand tan to take arguments in degrees instead of radiens (which is what I think the OP intended)
  • defining sec,csc and cot which are not part of the math package
  • inserting all the implied multiplication signs
  • replacing the exponentiation operator
\$\endgroup\$
  • \$\begingroup\$ @Doorknob How is brute-forcing expressions and comparing two values any more of a "real solution" than the others? \$\endgroup\$ – Ingo Bürk Oct 1 '14 at 6:15
  • \$\begingroup\$ @Emil Since you only compare two different values for `x', have you somehow ensured that simplifications are actually correct? \$\endgroup\$ – Ingo Bürk Oct 1 '14 at 6:15
  • \$\begingroup\$ Giving it a quick look I can't find incorrect simplifications (impressive), but to my understanding 1/3.sec(x)^2 is not valid output. \$\endgroup\$ – Ingo Bürk Oct 1 '14 at 6:20
  • 1
    \$\begingroup\$ @IngoBürk, all the answers were calculated by hand or with WolframAlpha first and I later compared these with the program's output. In two or three cases the program actually found simplifications that WolframAlpha did not output, but I could confirm that theses were correct too. But of course you're right, there could potentially be collisions. It's just that the nature of the functions in question make it quite unlikely that two distinct graphs should intersect at my two points within the used accuracy. I've seen collisions if I use just one point or if the two points are too close together. \$\endgroup\$ – Emil Oct 1 '14 at 6:52
  • 1
    \$\begingroup\$ @Emil Alright. I really love this solution btw! \$\endgroup\$ – Ingo Bürk Oct 1 '14 at 7:53
6
\$\begingroup\$

CJam, 1 + 3000 = 3001

Just as the baseline solution to give people something to beat:

l

This reads STDIN onto the stack, whose contents are printed at the end of the program.

I'm sure this can be beaten, but I'm also sure that many optimisations can't be implemented in the characters that would be gained.

\$\endgroup\$
  • \$\begingroup\$ Was it stated anywhere how to calculate the score? I like your method. However, I would not consider the newlines, so that the base score would be 3000. \$\endgroup\$ – Emil Sep 30 '14 at 8:34
  • \$\begingroup\$ @Emil "Try to minimize the sum of the program’s length and the total length of all of the solutions." – I had to read it several times as well. \$\endgroup\$ – Ingo Bürk Sep 30 '14 at 9:00
  • \$\begingroup\$ I wonder why Martin didn't use Golfscript. No need to explicitly read the input there =D \$\endgroup\$ – Ingo Bürk Sep 30 '14 at 9:02
  • \$\begingroup\$ I don't understand. How is this answer and the below one anyhow related to the question, which asks about trigonometry and stuff \$\endgroup\$ – Optimizer Sep 30 '14 at 9:29
  • 2
    \$\begingroup\$ @IngoBürk Because I don't know GolfScript. :P \$\endgroup\$ – Martin Ender Sep 30 '14 at 12:36
5
\$\begingroup\$

Javascript (438 + 2498 = 2936)

The object in the middle optionally contains simplified outputs based on the length of the input and the first character. Otherwise, the input is returned unmodified.

s='sin(x)';(p=prompt)({
    352:s+"^2cos(x)^3+2",
    307:"cos(x)/2",
    348:s+"8(1+cos(x)^2)",
    "81s":s+"^2tan(x)^7",
    "55s":"-sin(0.2-0.1x)^5",
    "39s":"2sec(2x+1)^2",
    "35c":"cos(4x)",
    "36-":0,
    173:s+"^2",
    "25s":0,
    294:s+"3-tan(x)",
    "27s":s+"2/cot(x)",
    "40c":"1+tan(x)^2+cot(x)^2",
    "48c":1,
    "41s":s+"+tan(x)-csc(x)-sec(x)",
    "26c":-1,
    "24t":"1+tan(x)^2",
    "96s":"2.5+1/cos(30)",
    "34t":"2tan(x)-cos(x)",
    353:0,
    "36s":"6sec(x)",
    "90s":"cot(x)^4csc(x)"
}[(i=p()).length+i[0]]||i)

The whitespace is just for decoration and not included in the character count.

It's a shame that adding all these solutions only saved me a few characters, but better than nothing. The simplification was done via wolframalpha – I'll just trust it.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.