Reference

Therefore

The therefore operator simplifies, as much as it can, the expression to its left.

y * (1 + 10%) => 1.1y
3 * (1 + 10%) => 3.3

It is a signal to Calca that you want it to perform a Calculation.

If the expression to its left is an undefined variable, then Calca attempts to solve for that variable by looking back in history for an equation or definition that uses the variable.

If it successfully solves for the variable, then it gives the simplified solution.

y = a*x^2 + b*x + c

x => [-0.5b/a + 0.5*sqrt(b^2 + 4a*y - 4a*c)/a, -0.5b/a - 0.5*sqrt(b^2 + 4a*y - 4a*c)/a]

a => y/x^2 - b/x - c/x^2

If it cannot solve for the variable, then it gives back the left and right hand sides of the equation that it got closest to solving:

10z + 100x = x^3 + x^2
x => 100x - x^3 - x^2 == -10z

Here we can see a limitation of Calca, it can't solve cubic equations (yet).

Definitions

Definitions assign a value to a name. They are highlighted in bold to make this clear:

name = 42
long name = -100

Anytime you use that name from then on, the assigned to value will be substituted:

5name => 210
name + long name => -58

Definitions cannot be re-defined, this is to support equations:

y(x) = m*x + b # Definition   
y(x) = 45      # Equation

x => -b/m + 45/m

Functions

You call functions by naming them and passing them a comma separated list of arguments wrapped in parenthesis:

# Function Definition
f(x, y) = x^2 + 2y^2

# Function Call
f(3, 5) => 59

You can also name arguments when you call the function:

f(y=5, x=3) => 59

All definitions are implicitly functions:

blend = start + 
    t * (end - start)

blend(t = 0) => start
blend(t = 0.8) => 0.8end + 0.2start
blend(t = 1) => end

Calca creates a default parameter list for a definition that does not specify one. That list is an ordered list of the variables that occur in the definition. For blend above, this list is (start, t, end) since that is the order in which the variables occurred. Because it's hard to remember this rule, it is highly recommended that you provide a parameter list when you have more than one variable.

You can specify the parameters manually in definition so that you don't have to name them every time you want to calculate the function.

blend2(t) = start +
    t * (end - start)

blend2(0) => start
blend2(0.8) => 0.8end + 0.2start
blend2(1) => end

Local Definitions

Functions can have local definitions to keep them organized using let name = value in expressions.

rotate(point, angle) =
    let x = point[0] in
    let y = point[1]in
    let ca = cos(angle) in
    let sa = sin(angle) in
    [x * ca - y * sa, 
     y * ca + x * sa]

rotate([10, 0], pi/3) => [5, 8.6603]

Input

Calca files are plain text files. When loaded, they are parsed into a set of lines or blocks which are evaluated one at a time starting from the top.

Multiple Lines make Blocks

If you have some math that takes multiple lines of text to write, then just make sure to indent those extra lines more than the first line. This is similar to bibliography formats.

long bit of math = this thing + that thing + one other thing

long bit of math( this thing = 100, that thing = 1) => one other thing + 101

Multiple Statements

You can put multiple statements on one line by separating them with a semicolon:

err(exp, res) = abs((exp - res)/exp); err(10,12) => 0.2; err(10,11) => 0.1

Markdown

Calca distinguishes between text annotations and calculations. If text is indented, then it assumed to be a calculation. If it is not, then Calca makes an educated guess as to whether you meant to make a calculation.

To force Calca to treat a line as code, indent it:

indented definition = true

To force Calca to treat a line as a text annotation, make sure it is unindented and ends with punctuation.

Headings Control Definition Availability

You can use headings with the standard Markdown of prefixing lines with the # symbol.

Definitions and equations written under a heading are only available in that heading and its children.

The next 3 sections demonstrate how variable values are bound to their heading.

This is a new level 5 heading

Define a:

a = 10
This is a level 6 heading

a has a value because this section is a child of the level 5 heading that defined a.

a => 10
This is a level 5 heading

There is no value for a because this section is not a child of the one that defined a.

a => a

Cultures

Calca defaults to working in an "invariant" culture where numbers have their decimal place marked using a period.

Other cultures, such as the French, prefer to use commas as the decimal separator.

You can switch Calca's culture any time using the #@culture directive. Here is an example of displaying and inputting numbers in different cultures.

a = 3,141.59

#@fr-FR

a => 3 141,59
a*a => 9 869 587,7281
b = 12 000,62

#@en-US

a => 3,141.59
a*a => 9,869,587.7281
b => 12,000.62

#@

a => 3,141.59

You can find your culture name in Microsoft's table of language culture names. An incorrectly specified culture name makes Calca revert back to the invariant culture.

Google Search

You can query Google from within Calca by writing a variable name and setting it equal to ?. Try uncommenting some of the following lines of code:

mass of earth = #?
goog = #?
10 km in miles = #?

This performs a Google search on your behalf and substitutes the ? with the result.

Matrices

Scalar Multiplication and Division:

[1, 2, 3] * 10 => [10, 20, 30]
[1, 2, 3] / 10 => [0.1, 0.2, 0.3]

Matrix Multiplication:

[1, 2, 3] * [1; 2; 3] => [14]
[1; 2; 3] * [1, 2, 3] => [1, 2, 3; 2, 4, 6; 3, 6, 9]

All other operators function element-wise:

[1, 6; 3, 8] + [5, 2; 7, 4] => [6, 8; 10, 12]
[1, 6; 3, 8] < [5, 2; 7, 4] => [true, false; true, false]

You can use any expression inside the matrix.

[foo, bar] * 2 => [2foo, 2bar]

Matrices are indexed using the [row, column] operator or the [index] operator. All indexing begins at 0.

a = [0, 1; 2, 3]

a[0,0] => 0
a[1,1] => 3
a[1,0] => 2

The index operator uses column-major ordering.

a[0] => 0
a[1] => 2
a[2] => 1

The index can be calculated from the row and column number.

index(row, col) = row + col*3
index(1,1) => 3col + 1,1
index(1,0) => 1

The transpose of a matrix can be calculated by raising it to the power of T:

[1, 2; 3, 4]^T => [1, 3; 2, 4]

Square Matrices

Square matrices also support having the inverse and determinate found.

a = [1, 2; 3, 4]

a^-1 => [-1.5, 0.5; 1, 0]
|a|  => -2

This makes solving linear equations easy:

a*x = [60; 70]

x => [-55; 60]

The symbolic inverse can also be taken but is limited to matrices whose dimension is less than 9.

s = [sx, 0, 0; 0, sy, 0; 0, 0, 1]
t = [1, 0, tx; 0, 1, ty; 0, 0, 1]

s * t * v = [vx; vy; 1]

v => [vx/sx - tx; vy/sy - ty; 1]

Ranges

Ranges represent lists of integers and are specified using minimum and maximum values, inclusive.

0:3 => 0:3

Indexing Matrices

Ranges can be used to index sub matrices:

a = [1, 2, 3; 4, 5, 6; 7, 8; 9]
a[0:1, 1:2] => [2, 3; 5, 6]

Generating Data

Using map, ranges can be used to generate data.

f(x) = 10x
map(f, 0:3) => [0, 10, 20, 30]

Map & Reduce

The map function applies a function to every element of a matrix:

map(cos, [0, pi/4, pi/3])
  => [1, 0.7071, 0.5]

map (10*x, [0, 1, 500])
  => [0, 10, 5000]

Map can also be used to combine multiple lists by passing them to a function of two parameters.

map (10*y + x, x = [1, 2], y = [3, 4])
  => [31, 42]

Reduce combines the elements of a matrix using a function that combines an accumulator and an individual element of the matrix. The result of the reduction of one element is passed on as the accumulator for the next function:

reduce (f, [1, 2, 3]) => f(f(1, 2), 3)

reduce (acc + x, [1, 2, 3])     => 6
reduce (acc + x + b, [1, 2, 3]) => 2b + 6

Reduce takes an optional third argument that specifies the initial value of the accumulator.

reduce (f, [1, 2, 3], 1000) => f(f(f(1000, 1), 2), 3)

Replicating Sum and Prod using Reduce

To make using reduce simple, here is how you can express the sum and prod functions in terms of it:

c = [10, 20, 30]

sum (x, c)        => 60
reduce (x + y, c) => 60

prod (x, c)       => 6000
reduce (x * y, c) => 6000

Logic Programming

And:

true && true => true
true && false => false
1 && 1 => 1
1 && 0 => 0

Or:

true || false => true
false || false => false
1 || 0 => 1
0 || 0 => 0

Not:

!true           => false
!(a && (b > 0)) => !a || (b <= 0)

Conditional Logic

The if condition then value else other value expression is used to give alternate values depending on some logic:

a(v) = if v < 0 then -v else v

a(-100)  => 100
a(100)   => 100
a(x + y) => if x + y < 0 then -x - y else x + y

Computer Numbers

You can specify numbers in hexadecimal and binary notation:

0xCC => 0xCC
0xFFFF_FFFF => 4294967295

0b101 => 0b101
0b1111_1111 => 0b11111111

These numbers are limited to 32-bits.

Here's a little function to get integral hexadecimal color values in the range [0, 255] from numbers in the range [0, 1].

color = round(f*0xFF)

color(1/3) => 0x55

Bit operations

You can use the & operator to do bitwise AND operations, and the | operator for bitwise OR operations.

0b0101 | 0b1010 => 0b1111
0b0101 & 0b1010 => 0

Don't confuse & and | with the logical && and || operators:

0b0100 | 1 => 0b101
0b0100 || 1 => 0b100
0b0100 & 1 => 0
0b0100 && 1 => 1

Complex Numbers

You can use the variable i to specify imaginary numbers:

1 + 2i   => 2i + 1
i*i      => -1
(1+2i)*i => i - 2
i^43     => -i

The square root function works well with imaginary numbers:

sqrt(-10000) => 100i
sqrt(i)      => 0.7071i + 0.7071

The conj function provides the complex conjugate:

re(z) = 1/2*(z + conj(z))
im(z) = 1/2i*(z - conj(z))

re(3 + 5i) => 3
im(3 + 5i) => 5

Derivatives

You can take the derivative a function with respect to a variable using the der function:

x(t) = 1/2*a*t^2 + v0*t + x0

der(x, t) => a*t + v0
der(x, a) => 0.5t^2

You can even specify a derivative to the nth degree using a third argument to der.

der(x, t, 2) => a

Sometimes derivatives can only be calculated "piece-wise". In that case, if expressions are used.

b = 3 + |a - 2|
der(b) => if a < 2 then -1 else 1

Standard Library

abs

The absolute value of an expression can be specified with the abs function or by surrounding the expression with bars |:

|-4| => 4
|-x| => |x|

abs(-4) => 4
abs(-x) => |x|

When abs is applied to square matrices, it produces the determinate:

|[a, b; c, d]| => a*d - b*c
abs([a, b; c, d]) => a*d - b*c

acos, asin, atan, atan2

The arc functions produce the inverses of the trigonometric functions:

acos(0.5) * 180/pi => 60
asin(0.5) * 180/pi => 30
atan(0.5) * 180/pi => 26.5651
atan2(1, 2) * 180/pi => 26.5651

conj

Calcaulates the complex conjugate of a complex number.

conj(3i)     => -3i
conj(2 + 3i) => -3i + 2
conj(a)      => a

cos, sin, tan

These are the standard circular trigonometry functions. Their arguments are in radians.

cos(0) => 1
cos(pi/3) => 0.5
cos(pi/4) => 0.7071

sin(0) => 0
sin(pi/3) => 0.866
sin(pi/4) => 0.7071

cosh, sinh, tanh

These are the hyperbolic trigonometry functions. Their arguments are in radians.

cosh(0) => 1
cosh(pi/3) => 1.6003
cosh(pi/4) => 1.3246

sinh(0) => 0
sinh(pi/3) => 1.2494
sinh(pi/4) => 0.8687

ceil

Returns the ceiling of a number.

ceil(2.1)  => 3
ceil(-2.1) => -2

der

Calculates the derivative of a function. See [Derivatives][] for details.

dot

Calculates the inner product of two matrices:

dot([a, b], [c, d]) => a*c + b*d

dot([1, 0], [0.7, 0.3]) => 0.7

floor

Returns the floor of a number.

floor(2.1)  => 2
floor(-2.1) => -3

inv

Finds the multiplicative inverse of a number or matrix. It is equivalent to raising to a power of -1 or dividing 1 by the number.

inv(2) => 0.5
inv(a) => 1/a

inv([1, 2; 3, 4]) => [-2, 1; 1.5, -0.5]

jacobian

The Jacobian matrix is the matrix of all first-order partial derivatives of a vector-valued function given by m real-valued component functions.

The Jacobian of 1 function with 2 variables is a 1x2 matrix:

jacobian(2x/y) => [2/y, -2x/y^2]

The Jacobian of 2 functions of 2 variables is a 2x2 matrix:

jacobian(2x/y, 3x) => [2/y, -2x/y^2; 3, 0]

The functions can also be specified inside a matrix:

jacobian([2x+y, y/x]) => [2, 1; -y/x^2, 1/x]

You can specify which variables with respect to which the Jacobian should be taken by passing them as single variable arguments:

jacobian([2x+y, y/x], x, z) => [2, 0; -y/x^2, 0]

log, log2, log10, ln

Logarithms are specified using the log function. It takes two args: the value and the base of the logarithm.

log(100, 10) => 2
log(x, 10)   => log10(x)

log(100, e)  => 4.6052
log(x, e)    => ln(x)

There are shortcut versions for some common bases:

log2(1000)  => 9.9658
log10(1000) => 3
ln(1000)    => 6.9078

Logarithms expand multiplication into individual logarithms:

log(x*y, b) => log(x, b) + log(y, b)
log(x/y, b) => log(x, b) - log(y, b)

prod

The first argument is the function to multiply.

The second argument names the variable to multiply and gives the range.

prod(x, 1:3)       => 6
prod(x + a, 1:3)   => (a + 1)*(a + 2)*(a + 3)
prod(x + a, a=1:3) => (x + 1)*(x + 2)*(x + 3)

Instead of ranges, you can specify values from a matrix:

prod(x, [1, 2, 3])   => 6
prod(x^2, [1, 2, 3]) => 36

round

Rounds a number to the nearest integer. It uses the standard computer odd/even rules for numbers half way between integers.

round(2.1)     => 2
round(-2.1)    => -2

round(1.5)     => 2

round(2.5)     => 2
round(2.50001) => 3

sqrt

This is a short cut for writing the square root of a value:

sqrt(9) => 3
sqrt(a) => a^0,5
a^0.5   => sqrt(a)

sum

Summation is represented with the sum function.

The first argument is the function to sum.

The second argument names the variable to sum and gives the range.

sum(x*x, x=1:5)   => 55

sq(v) = v^2

sum(sq, x=1:5)    => 5v^2
sum(sq(x), x=1:5) => 55

taylor

Taylor series approximate functions at a point using a polynomial. It's great for simplifying otherwise complex or hard-to-compute mathematics.

f(x) = sin(x) + cos(x)

taylor(f, x = 0, 1) => x + 1
taylor(f, x = 0, 2) => x - 0.5x^2 + 1
taylor(f, x = 0, 3) => x - 0.5x^2 - 0.1667x^3 + 1

truncate

Truncates a number.

truncate(2.1)  => 2
truncate(-2.1) => -2

Glossary

Definition is the assignment of an expression to a name. Definitions can also include an optional parameter list if they are meant to represent functions.

Equation is a set of two expressions that are set equal to each other using the = operator.

Expression is an algebraic value comprised of numbers, variables, and operators manipulating those numbers and variables.