- Google Search
- Map & Reduce
- Logic Programming
- Computer Numbers
- Complex Numbers
- Standard Library
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 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
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
Functions can have local definitions to keep them organized using
let name = value in expressions.
rotate(point, angle) = let x = point in let y = pointin 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]
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
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
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
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
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 => 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
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.
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.
Scalar Multiplication and Division:
[1, 2, 3] * 10 => [10, 20, 30] [1, 2, 3] / 10 => [0.1, 0.2, 0.3]
[1, 2, 3] * [1; 2; 3] =>  [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 a => 2 a => 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
[1, 2; 3, 4]^T => [1, 3; 2, 4]
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 represent lists of integers and are specified using minimum and maximum values, inclusive.
0:3 => 0:3
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]
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
true && true => true true && false => false 1 && 1 => 1 1 && 0 => 0
true || false => true false || false => false 1 || 0 => 1 0 || 0 => 0
!true => false !(a && (b > 0)) => !a || (b <= 0)
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
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
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
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
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
You can take the derivative a function with respect to a variable using the
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(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
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|
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
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
Returns the ceiling of a number.
ceil(2.1) => 3 ceil(-2.1) => -2
Calculates the derivative of a function. See [Derivatives] for details.
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
Returns the floor of a number.
floor(2.1) => 2 floor(-2.1) => -3
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]
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)
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
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
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)
Summation is represented with the
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 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
Truncates a number.
truncate(2.1) => 2 truncate(-2.1) => -2
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
Expression is an algebraic value comprised of numbers, variables, and operators manipulating those numbers and variables.