Using the SymEngine gem


SymEngine is a module in the extensions, and the classes are a part of it. So first you fire up the interpreter and load the file


In [1]:
require 'symengine'


Out[1]:
true

Go ahead and try a function


In [2]:
print SymEngine.ascii_art


 _____           _____         _         
|   __|_ _ _____|   __|___ ___|_|___ ___ 
|__   | | |     |   __|   | . | |   | -_|
|_____|_  |_|_|_|_____|_|_|_  |_|_|_|___|
      |___|               |___|          

This shows that we have successfully loaded the module.

SymEngine::Symbol

Just like there are variables like x, y, and z in a mathematical expression or equation, we have SymEngine::Symbol in SymEngine to represent them. To use a variable, first we need to make a SymEngine::Symbol object with the string we are going to represent the variable with.


In [3]:
puts x = SymEngine::Symbol.new("x")
puts y = SymEngine::Symbol.new("y")
puts z = SymEngine::Symbol.new("z")


x
y
z

Then we can construct expressions out of them


In [4]:
e = (x-y)*(x**y/z)
e.to_s


Out[4]:
"x**y*(x - y)/z"

In SymEngine, every object is an instance of Basic or its subclasses. So, even an instance of SymEngine::Symbol is a Basic object.


In [5]:
x.class


Out[5]:
SymEngine::Symbol

In [6]:
x.is_a? SymEngine::Basic


Out[6]:
true

Now that we have an expression, we would like to see it's expanded form using #expand


In [7]:
f = e.expand()
f.to_s


Out[7]:
"x**(1 + y)/z - x**y*y/z"

Or check if two expressions are same


In [8]:
f == - (x**y*y/z) + (x**y*x/z)


Out[8]:
true

But e and f are not equal since they are only mathematically equal, not structurally


In [9]:
e == f


Out[9]:
false

Let us suppose you want to know what variables/symbols your expression has. You can do that with the #free_symbols method. The method #free_symbols returns a Set of the symbols that are in an expression.


In [10]:
f.free_symbols


Out[10]:
#<Set: {#<SymEngine::Add(x)>, #<SymEngine::Add(y)>, #<SymEngine::Add(z)>}>

Let us use #map method to see the elements of the Set.


In [11]:
f.free_symbols.map { |x| x.to_s }


Out[11]:
["x", "y", "z"]

#args returns the terms of the expression,


In [12]:
f.args.map { |x| x.to_s }


Out[12]:
["-x**y*y/z", "x**(1 + y)/z"]

or if it is a single term it breaks down the elements


In [13]:
f.args[0].args.map { |k| k.to_s }


Out[13]:
["-1", "x**y", "y", "z**(-1)"]

SymEngine::Integer

You can make objects of class SymEngine::Integer. It's like regular Integer in ruby kernel, except it can do all the operations a Basic object can like arithmetic operations, etc.


In [14]:
a = SymEngine::Integer.new(12)
b = SymEngine::Integer.new(64)
a**b


Out[14]:
1168422057627266461843148138873451659428421700563161428957815831003136

And yes it can support numbers of arbitrarily large length.


In [15]:
(a**x).to_s


Out[15]:
"12**x"

SymEngine::Rational

You can also make objects of class SymEngine::Rational that is the SymEngine counterpart for Rationals in Ruby.


In [16]:
c = Rational('2/3')
d = SymEngine(c)


Out[16]:
2/3

Like any other Basic object arithmetic operations can be done on this one too.


In [17]:
(a-d).to_s


Out[17]:
"34/3"

You need not create an instance of SymEngine::Integer or SymEngine::Rational, every time you want to use them in an expression that uses many Integers. Let us say you already have Integer/Rational object. Even then you can use them without having to create a new SymEngine object.


In [18]:
k = (1 / (x * y) - x * y + 2) * (c + x * y) # c is a Rational object, not SymEngine::Rational
k.to_s


Out[18]:
"(2/3 + x*y)*(2 + 1/(x*y) - x*y)"

As you can see, ruby kernel Integers and Rationals interoperate seamlessly with the SymEngine objects.


In [19]:
k.expand.to_s


Out[19]:
"7/3 + (2/3)*1/(x*y) + (4/3)*x*y - x**2*y**2"

SymEngine::RealDouble

SymEngine::RealDouble can be constructed by converting any ruby Float into SymEngine


In [20]:
d = SymEngine(1.2)


Out[20]:
1.2

SymEngine::ComplexDouble

SymEngine::ComplexDouble can be constructed by converting any ruby Complex into SymEngine


In [21]:
c = SymEngine(Complex(2.3, 3.2))


Out[21]:
2.3 + 3.2*I

SymEngine::RealMPFR

SymEngine::RealMPFR can be constructed either by converting any Ruby BigDecimal into SymEngine, or using the constructor to express any real number with a given number of bits of precision


In [22]:
require 'bigdecimal'
r1 = SymEngine(BigDecimal("12.3"))
r2 = SymEngine::RealMPFR.new(12.3, 200)


Out[22]:
12.300000000000000710542735760100185871124267578125000000000000

SymEngine::ComplexMPC

SymEngine::RealMPC can be constructed by arithmatic operations of any SymEngine::RealMPFR objects, as shown below.


In [23]:
i = SymEngine::I
c1 = r1 + i * r2


Out[23]:
12.300000000000000000000000000000000000000000000000000000000002 + 12.300000000000000710542735760100185871124267578125000000000000*I

SymEngine::Constant - SymEngine Constants

SymEngine offers the following constants


In [24]:
i = SymEngine::I
e = SymEngine::E
eg = SymEngine::EULER_GAMMA
pi = SymEngine::PI

i.inspect + e.inspect + eg.inspect + pi.inspect


Out[24]:
"#<SymEngine::Complex(I)>#<SymEngine::Constant(E)>#<SymEngine::Constant(EulerGamma)>#<SymEngine::Constant(pi)>"

SymEngine::TrigFunction

sin, cos, tan, cosec, sec, cot, asin, acos, atan, acosec, asec, acot are available as shown below:


In [25]:
i1 = SymEngine::sin(pi)
i2 = SymEngine::cos(0.2)
i3 = SymEngine::tan(pi/4)
i4 = SymEngine::csc(pi/2)
i5 = SymEngine::sec(0.2)
i6 = SymEngine::cot(pi/4)

print "sin(pi): ", i1,"\ncos(0.2): ", i2, "\ntan(pi/4): ",  i3, "\ncsc(pi/2): ", i4, "\nsec(0.2): ",  i5,"\ncot(pi/4): ",  i6, "\n"


sin(pi): 0
cos(0.2): 0.980066577841242
tan(pi/4): 1
csc(pi/2): 1
sec(0.2): 5.03348954767234
cot(pi/4): 1

In [26]:
i1 = SymEngine::asin(1)
i2 = SymEngine::acos(0)
i3 = SymEngine::atan(5)
i4 = SymEngine::acsc(1)
i5 = SymEngine::asec(0.2)
i6 = SymEngine::acot(0.5)

print "i1: ", i1,"\ni2: ", i2, "\ni3: ",  i3, "\ni4: ", i4, "\ni5: ",  i5,"\ni6: ",  i6, "\n"


i1: (1/2)*pi
i2: (1/2)*pi
i3: atan(5)
i4: (1/2)*pi
i5: 0.0 - 2.29243166956118*I
i6: 1.10714871779409

SymEngine::HyperbolicFunction

sinh, cosh, tanh, cosech, sech, coth, asinh, acosh, atanh, acosech, asech, acoth are available as shown below:


In [27]:
i1 = SymEngine::sinh(pi)
i2 = SymEngine::cosh(0.2)
i3 = SymEngine::tanh(pi/4)
i4 = SymEngine::csch(pi/2)
i5 = SymEngine::sech(0.2)
i6 = SymEngine::coth(pi/4)

print "sinh(pi): ", i1,"\ncosh(0.2): ", i2, "\ntanh(pi/4): ",  i3, "\ncsch(pi/2): ", i4, "\nsech(0.2): ",  i5,"\ncoth(pi/4): ",  i6, "\n"


sinh(pi): sinh(pi)
cosh(0.2): 1.02006675561908
tanh(pi/4): tanh((1/4)*pi)
csch(pi/2): csch((1/2)*pi)
sech(0.2): 0.980327997644725
coth(pi/4): coth((1/4)*pi)

In [28]:
i1 = SymEngine::asinh(1)
i2 = SymEngine::acosh(0)
i3 = SymEngine::atanh(5)
i4 = SymEngine::acsch(1)
i5 = SymEngine::asech(0.2)
i6 = SymEngine::acoth(0.5)

print "i1: ", i1,"\ni2: ", i2, "\ni3: ",  i3, "\ni4: ", i4, "\ni5: ",  i5,"\ni6: ",  i6, "\n"


i1: log(1 + 2**(1/2))
i2: acosh(0)
i3: atanh(5)
i4: log(1 + 2**(1/2))
i5: asech(0.2)
i6: 0.549306144334055 + 1.5707963267949*I

Number Theory Functions

Several Number Theory functions are available in SymEngine.

GCD and LCM


In [29]:
gcd = SymEngine::gcd(45, 40)
lcm = SymEngine::lcm(45, 40)

print "for 45 and 40,\ngcd is: ", gcd, "\nlcm is: ",lcm, "\n"


for 45 and 40,
gcd is: 5
lcm is: 360

Next Prime


In [30]:
np = SymEngine::nextprime(5)


Out[30]:
7

Quotient


In [31]:
q = SymEngine::quotient(5, 2)


Out[31]:
2

Lucas and Fibonacci series


In [32]:
l = SymEngine::lucas(3)
f = SymEngine::fibonacci(3)

p l, f


#<SymEngine::Integer(4)>
#<SymEngine::Integer(2)>
Out[32]:
[#<SymEngine::Integer(4)>, #<SymEngine::Integer(2)>]

Binomials


In [33]:
b = SymEngine::binomial(5, 2)


Out[33]:
10