16
\$\begingroup\$

The split-complex numbers, also known as "perplex numbers" are similar to the complex numbers. Instead of i^2 = -1, however, we have j^2 = 1; j != +/-1. Each number takes the form of z = x + j*y.

In one attempt to limit the complexity of this challenge, I will use the symbol - to represent negation, as there will not be any subtraction.

Here are some examples for your viewing pleasure:

6 * 9 = 54            // real numbers still act normally
5 + -7 = -2
j*1 + j*1 = j*2           // two `j`s added together make a j*2
7 * j*1 = j*7           // multiplication is commutative & associative
j*1 + 2 = 2+j*1           // like oil and water, "combine" to form a split-complex number
j*1 + j*-3 = j*-2          // seems okay so far
j*j*1 = j*-1*j*-1 = 1     // kinda sketchy, but such is its inherent nature
j*j*-1 = j*-1*j*1 = -1  
(2+j*3)+(4+j*7) = 6+j*10  // combine like terms
7 * (2+j*3) = 14+j*21 // distributive property
j * (2+j*3) = (j*2) + (j*j*3) = 3+j*2   // since j^2 = 1, multiplying my j "swaps" the coefficients
(2+j*3)*(4+j*7) = (2*4)+(2*j*7)+(j*3*4)+(j*3*j*7) = 8+j*14+j*12+21 = 29+j*26 // a complete multiplication

Challenge

The goal of this challenge is to evaluate an expression with split-complex numbers.

This is code-golf, the fewest bytes wins.

Input

Input will be a single line containing only the symbols +*()-, the digits 0123456789, and the letter j, with an optional newline. This string represents an expression, using infix notation and operator precedence (multiplication before addition, with parenthesis grouping).

  • The symbol - will always represent negation, never subtraction. If you so desire, you can replace - with either _ or ~ for ease of I/O.
  • Parenthesis can be nested up to three times to denote grouping: (1+(1+(1)))
  • The letter j will never be directly prefixed with negation, and will always be followed by *.
  • Parentheses will not be preceded by negation -(7), but instead like -1*(j*5+2)
  • There will never be implicit operations. All multiplication will be expressed as (7)*7 instead of (7)7, and as j*5 instead of j5.
  • No leading zeros.

Output

Output will be in the form of X+j*Y, where X and Y can be any integer. If an integer is negative, it should be prefixed with the negation sign.

Additional Restrictions

Although I am not aware of any language with native support, built-ins that deal with split-complex numbers are forbidden. Regular complex numbers are fair game.

Test Cases

Similar to the above examples, but tidied up. Input on one line and output the line beneath.

(2+j*3)+(4+j*7)
6+j*10

(2+j*3)*(4+j*7)
29+j*26

(-5+j*1+j*2+2)*(4+j*7)
9+j*-9

(1+j*-1)*(1+j*1)
0+j*0 // this is why division does not exist.

j*((j*-1)+2)
-1+j*2

(2+(5+-1*(j*1))+2)
9+j*-1
\$\endgroup\$
13
\$\begingroup\$

Python 2, 62 bytes

def f(s):b,a=[eval(s)/2.for j in-1,1];print'%d+j*%d'%(a+b,a-b)

We simply evaluate the expression s with j=1 and j=-1, and output half their sum and half their difference as the coefficients of 1 and j.

This works because both j=1 and j=-1 satisfy the defining equation defining equation j*j==1. So, the original and simplified expressions must be equal for both these values. The simplified expression is linear, so this gives two linear equations in two unknowns:

x + 1*y  = s(1)  = 2*a
x - 1*y  = s(-1) = 2*b

which is solved by x=a+b, y=a-b.

\$\endgroup\$
  • \$\begingroup\$ A language with matrix operations could also evaluate the expression with j=[0 1; 1 0] and read off coefficients from the top row. \$\endgroup\$ – xnor Jan 10 '16 at 9:40
2
\$\begingroup\$

Python 2, 258

class c(complex):__mul__=lambda s,o:c(s.real*o.real+s.imag*o.imag,s.real*o.imag+s.imag*o.real);__add__=lambda s,o:c(sum(map(complex,[s,o])))
import re
r=eval(re.sub("j","c(0,1)",re.sub(r"(-?\d+)",r"c(\1)",raw_input())))
print`int(r.real)`+"+j*"+`int(r.imag)`

This is probably not the best approach, but it was the first time that OOP looked like a passable idea in Python for code golf, so why not?

Creates a class c that inherits from complex but has a different mul operation. The add operation is also changed so that it returns an object of type c and not complex, this behaviour is necessary to prevent the case of (a + b) * (c + d) doing complex multiplication instead of this special kind.

The input string is then converted into a string that can be evaluated naturally by python. It does this by changing every number into c(number) and then every j into c(0,1).

Try it online or run a Test Suite

\$\endgroup\$
1
\$\begingroup\$

GAP, 38 bytes

j:=X(Integers,"j");f:=t->t mod(j^2-1);

First j is defined to be an indeterminate, so we can create polynomials in j. To get the corresponding perplexing number, we reduce (i.e. take the remainder of polynomial division) by j^2-1. This gives a linear (or constant) term, and we can rely on GAP's ability to output polynomials.

Examples:

gap> f((2+j*3)+(4+j*7));
10*j+6
gap> f((1+j*-1)*(1+j*1));
0

Caveat: 1. This does not take a string as input, but a real term in GAP's language. To fix, I could use EvalString. 2. The output is nice and clear, but not exactly as specified: Order is changed, and unnecessary zeroes are suppressed. I think and hope this is still in the spirit of the challenge, otherwise I guess I'd be better off using @xnor's matrix approach.

\$\endgroup\$
  • 1
    \$\begingroup\$ Mathematica's PolynomialMod[#,j^2-1]& has similar properties. Indeed, if we never multipled more than two perplex numbers together (like the test cases don't), then Expand@#/.j^2->1 suffices. \$\endgroup\$ – Greg Martin Jan 15 '17 at 18:47
  • \$\begingroup\$ Similarly, t->t%(j^2-1) in Pari/GP. \$\endgroup\$ – alephalpha Jun 5 '17 at 7:14
1
\$\begingroup\$

Axiom, 20 42 bytes

f(x,n)==x^(n rem 2);m:=rule('j^n==f('j,n))

the preceding solution have a problem if n<0 in j^n but this it seems more solid, and advise well where there is something wrong, even if the perfection would be return example j^1.2 or j^sqrt(-1) the same expression not evaluate

(9) -> f(x,n)==x^(n rem 2);m:=rule('j^n==f('j,n))
         n
   (9)  j  == 'f(j,n)
                    Type: RewriteRule(Integer,Integer,Expression Integer)
(10) -> [m((2+j*3)+(4+j*7)), m((2+j*3)*(4+j*7)), m((-5+j*1+j*2+2)*(4+j*7))]
   (10)  [10j + 6,26j + 29,- 9j + 9]
                                            Type: List Expression Integer
(11) -> [m((1+j*-1)*(1+j*1)), m(j*((j*-1)+2)), m(2+(5+-1*(j*1))+2)]
   (11)  [0,2j - 1,- j + 9]
                                            Type: List Expression Integer
(12) -> [m(j*j*j*j),m(j*j*j),m(j^200)]
   (12)  [1,j,1]
                                            Type: List Expression Integer
(13) -> [m(j^0),m(j^-1),m(j^-2), m(j^-3)]
            1   1
   (13)  [1,-,1,-]
            j   j
                                            Type: List Expression Integer
(14) -> m(j^(3.4))
   There are no library operations named m
      Use HyperDoc Browse or issue

if i not follow some law of the question: say me that and i add "not competitive". I mean it as one axiom for simplify formula

\$\endgroup\$
0
\$\begingroup\$

Batch, 52 bytes

@set/aj=1,a=%1,j=-1,a-=b=(a-(%1))/2
@echo %a%+j*%b%

After seeing @xnor's excellent answer nomination I felt compelled to port 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.