Add and multiply perplexing numbers

16

2

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

PhiNotPi

Posted 2016-01-09T15:44:10.797

Reputation: 26 739

Answers

13

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.

xnor

Posted 2016-01-09T15:44:10.797

Reputation: 115 687

A language with matrix operations could also evaluate the expression with j=[0 1; 1 0] and read off coefficients from the top row. – xnor – 2016-01-10T09:40:57.823

2

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

FryAmTheEggman

Posted 2016-01-09T15:44:10.797

Reputation: 16 206

1

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.

Christian Sievers

Posted 2016-01-09T15:44:10.797

Reputation: 6 366

1Mathematica'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. – Greg Martin – 2017-01-15T18:47:27.603

Similarly, t->t%(j^2-1) in Pari/GP. – alephalpha – 2017-06-05T07:14:29.443

1

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

RosLuP

Posted 2016-01-09T15:44:10.797

Reputation: 3 036

0

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.

Neil

Posted 2016-01-09T15:44:10.797

Reputation: 95 035