# The Standard Library (stdlib)

Broad collection of Rel functions that perform essential and commonly used tasks.

add[x, y]
x + y


Examples:

• 1 + 3 is an expression with value 4
• add[1, 3] is an expression with value 4
• add(1, 3, 4) is a formula that is true.
1 + 3 = 4add[1, 3] = 4equal(add(1, 3, 4), true)

#### Definition#

@inlinedef add(x, y, z) = rel_primitive_add(x, y, z)@inlinedef (+)(x, y, z) = add(x, y, z)

## subtract#

subtract[x, y]
x - y


Subtraction.

Examples:

8 - 5 = 3subtract[2, 3] = -1equal(subtract(8, 5, 3), true)

#### Definition#

@inlinedef subtract(x, y, z) = rel_primitive_subtract(x, y, z)@inlinedef (-)(x, y, z) = subtract(x, y, z)

## divide#

divide[x, y]
x / y


Division.

• Float64 / Float64 = Float64
• Int64 / Int64 = Float64
• Int64 / Float64 = Float64
• Float64 / Int64 = Float64
• FixedDecimal / FixedDecimal = FixedDecimal
• Int64 / FixedDecimal = FixedDecimal
• FixedDecimal / Int64 = FixedDecimal

Examples:

3.4 / 2 = 1.7divide[6, 3] = 2.0equal(divide(6, 3, 2.0), true)equal(divide(6, 3, 2), false)

#### Definition#

@inlinedef divide[x, y] = rel_primitive_divide[x, y]@inlinedef (/)(x, y, z) = divide(x, y, z)

## trunc_divide#

trunc_divide[x, y]


Integer Division.

Quotient from Euclidean division. Computes x/y rounded towards zero.

Derives to false when y = 0 for Integer arguments.

Examples:

trunc_divide[5, 2] = 2trunc_divide[-5, 2] = -2trunc_divide[5.1, 2] = 2.0empty(trunc_divide[5, 0])

#### Definition#

@inlinedef trunc_divide[x, y] = rel_primitive_trunc_divide[x, y]@inlinedef (÷)(x, y, z) = trunc_divide(x, y, z)

## floor_divide#

floor_divide[x, y]


Floor Division.

Largest integer less than or equal to x/y. Computes x/y rounded towards negative infinity.

Derives to false when y = 0 for Integer arguments.

Examples:

floor_divide[5, 2] = 2floor_divide[-5, 2] = -3floor_divide[5.1, 2] = 2.0

#### Definition#

@inlinedef floor_divide[x, y] = rel_primitive_floor_divide[x, y]

## remainder#

remainder[x, y]
x % y


Remainder.

Remainder from Euclidean division, returning a value of the same sign as x, and smaller in magnitude than y. This value is always exact.

Satisfies x = (x / y) * y + (x % y).

Derives to false when y = 0 for Integer arguments.

Examples:

8 % 3 = 2remainder[8, 3] = 2remainder[8, -3] = 2remainder[-8, 3] = -2

#### Definition#

@inlinedef remainder[x, y] = rel_primitive_remainder[x, y]@inlinedef (%)(x, y, z) = remainder(x, y, z)

## modulo#

modulo[x, y]


Modulus after division, returning in the range [0,y), if y is positive, or (y,0] if y is negative.

Satisfies x = floor_divide[x,y] * y + modulo[x, y].

Derives to false when y = 0 for Integer arguments.

Examples:

modulo[8, 3] = 2modulo[8, -3] = -1modulo[-8, 3] = 1

#### Definition#

@inlinedef modulo[x, y] = rel_primitive_modulo[x, y]

## multiply#

multiply[x, y]
x * y


Multiplication.

Examples:

3 * 2 = 6equal(multiply(3.0, 2, 6.0), true)

#### Definition#

@inlinedef multiply[x, y] = rel_primitive_multiply[x, y]@inlinedef (*)(x, y, z) = multiply(x, y, z)

## bitwise_and#

bitwise_and[x, y]


Bitwise and of two integers.

Example:

bitwise_and[3,2] = 2bitwise_and[0x10011, 0x11100] = 0x00010000

#### Definition#

@inlinedef bitwise_and[x, y] = rel_primitive_bitwise_and[x, y]

## bitwise_or#

bitwise_or[x, y]


Bitwise or of two integers.

Example:

bitwise_or[3, 2] = 3bitwise_or[0x00011, 0x11100] = 0x00011111

#### Definition#

@inlinedef bitwise_or[x, y] = rel_primitive_bitwise_or[x, y]

## bitwise_xor#

bitwise_xor[x, y]


Bitwise xor of two integers.

Example:

bitwise_xor[3, 2] = 1bitwise_xor[0x00011, 0x11100] = 0x00011111

#### Definition#

@inlinedef bitwise_xor[x, y] = rel_primitive_bitwise_xor[x, y]

## bitwise_left_shift#

bitwise_left_shift[x, n]


Bitwise left shift of an integer x by n bits.

Examples:

bitwise_left_shift[8, 1] = 16bitwise_left_shift[1, 10] = 1024bitwise_left_shift[0xF, 1] = 0x1d

#### Definition#

@inlinedef bitwise_left_shift[x, n] = rel_primitive_bitwise_left_shift[x, n]

## bitwise_right_shift#

bitwise_right_shift[x, n]


Bitwise right shift of an integer x by n bits while preserving the sign.

Examples:

bitwise_right_shift[1024, 1] = 512bitwise_right_shift[-1024, 1] = -512

#### Definition#

@inlinedef bitwise_right_shift[x, n] = rel_primitive_bitwise_signed_right_shift[x, n]

## bitwise_unsigned_right_shift#

bitwise_unsigned_right_shift[x,n]


Bitwise right shift of an integer by n bits.

Examples:

bitwise_unsigned_right_shift[8, 1] = 4bitwise_unsigned_right_shift[-8, 1] = 9223372036854775804

#### Definition#

@inlinedef bitwise_unsigned_right_shift[x, n] = rel_primitive_bitwise_unsigned_right_shift[x, n]

## bitwise_not#

bitwise_not[x]


Bitwise not of an integer.

Examples:

bitwise_not[8] = -9bitwise_not[-9] = 8bitwise_not[0x00011] = 0xffffffee

#### Definition#

@inlinedef bitwise_not[x] = rel_primitive_bitwise_not[x]

## power#

power[x, y]
x ^ y


Exponentiation: $x$ to the power of $y$.

Examples:

power[2, 3] = 8power[3.0, 2] = 9.0power[9, 0.5] = 3.0

#### Definition#

@inlinedef power[x, y] = rel_primitive_power[x, y]@inlinedef (^)(x, y, z) = power(x, y, z)

## floor#

floor[x]


Round down to the nearest integer.

Examples:

floor[4.5] = 4.0floor[-4.5] = -5.0floor[4] = 4

#### Definition#

@inlinedef floor[x] = round[:ROUND_DOWN, x]

## floor_to_int#

floor_to_int[x]


General float-to-int conversion, floor. Argument must be a float.

Examples:

floor_to_int[3.1] = 3floor_to_int[-3.1] = -4floor_to_int[3] : error

#### Definition#

@inlinedef floor_to_int[x] = float_int_convert[floor[x]]

## ceil#

ceil[x]


Round up to the nearest integer.

Examples:

ceil[4.5] = 5.0ceil[-4.5] = -4.0ceil[4] = 4

#### Definition#

@inlinedef ceil[x] = round[:ROUND_UP, x]

## trunc#

trunc[x]


Round toward zero to the nearest integer. Result has the same type as the argument.

Examples:

trunc[3.9] = 3.0trunc[-4.9] = -4.0trunc[4] = 4

#### Definition#

@inlinedef trunc[x] = round[:ROUND_TO_ZERO, x]

## trunc_to_int#

trunc_to_int[x]


General float-to-int conversion, truncating. Argument must be a float.

Examples:

trunc_to_int[3.1] = 3trunc_to_int[-3.1] = -3trunc_to_int[3] : error

#### Definition#

@inlinedef trunc_to_int[x] = float_int_convert[trunc[x]]

## round#

round[mode, x]


Round to the nearest integer according to the given rounding mode.

#### Definition#

@inlinedef round(mode, x, rounded) = {    (mode = :ROUND_UP,                rounded = rel_primitive_round_up[x]);    (mode = :ROUND_DOWN,              rounded = rel_primitive_round_down[x]);    (mode = :ROUND_NEAREST,           rounded = rel_primitive_round_nearest[x]);    (mode = :ROUND_NEAREST_TIES_AWAY, rounded = rel_primitive_round_nearest_ties_away[x]);    (mode = :ROUND_NEAREST_TIES_UP,   rounded = rel_primitive_round_nearest_ties_up[x]);    (mode = :ROUND_TO_ZERO,           rounded = rel_primitive_round_to_zero[x]) }

## maximum#

maximum[x, y]


Maximum of two arguments. The arguments should have the same type.

Examples:

maximum[3, 4] = 4maximum[3.0, 4.0] = 4.0

#### Definition#

@inlinedef maximum[x, y] = rel_primitive_max[x, y]

## minimum#

minimum[x, y]


Minimum of two arguments. The arguments should have the same type.

Examples:

minimum[3, 4] = 3minimum[3.0, 4.0] = 3.0

#### Definition#

@inlinedef minimum[x, y] = rel_primitive_min[x, y]

## abs#

abs[x]


The absolute value of x.

Examples:

abs[-2] = 2abs[-2.0] = 2.0

#### Definition#

@inlinedef abs[x] = rel_primitive_abs[x]

## sqrt#

sqrt[x]


The non-negative square root of x.

Defined for non-negative x.

#### Definition#

@inlinedef sqrt[x] = rel_primitive_sqrt[x]

## log#

log[x, y]


Logarithm of y with given base x.

Example:

log[2, 8] = 3.0

#### Definition#

@inlinedef log[x, y] = rel_primitive_log[x, y]

## log10#

log10[x]


Base 10 logarithm.

log10[1000] = 3.0

#### Definition#

@inlinedef log10[x] = rel_primitive_log10[x]

## natural_log#

natural_log[x]


Natural logarithm (ln).

#### Definition#

@inlinedef natural_log[x] = rel_primitive_natural_log[x]

## natural_exp#

natural_exp[x]


Exponentiation with the base of the natural log, e.

#### Definition#

@inlinedef natural_exp[x] = rel_primitive_natural_exp[x]

## erf#

erf[x]


Returns the error function of x.

Examples:

erf[2] = 0.9953222650189527erf[-0.5] = -0.5204998778130465

#### Definition#

@inlinedef erf[x] = rel_primitive_error_function[x]

## erfinv#

erfinv[x]


Returns the inverse error function of x.

Examples:

erfinv[0.1] = 0.08885599049425769erfinv[-0.5] = -0.4769362762044699erfinv[erf[1]] = 1.0

#### Definition#

@inlinedef erfinv[x] = rel_primitive_error_function_inverse[x]

## cbrt#

cbrt[x]


The cube root of x.

Example:

cbrt[27] = 3.0

#### Definition#

@inlinedef cbrt[x] = rel_primitive_cbrt[x]

## factorial#

factorial[x]


Factorial of x

#### Definition#

@inlinedef factorial[x] = rel_primitive_factorial[x]

## sign#

sign[x]


The sign of x: either 0, -1, or 1.

#### Definition#

@inlinedef sign[x] = rel_primitive_sign[x]

## pi_float64#

pi_float64


The constant pi.

Example:

cos[pi_float64] = -1.0

#### Definition#

@inlinedef pi_float64 = 3.14159265358979323846

## sin#

sin[x]


Sine of x (given in radians). Example:

sin[pi_float64/2] = 1.0

#### Definition#

@inlinedef sin[x] = rel_primitive_sin[x]

## asin#

asin[x]


Inverse sine (in radians). Gives an error if ${\rm abs}[x] > 1$.

Example:

asin[1] = 1.5707963267948966

#### Definition#

@inlinedef asin[x] = rel_primitive_asin[x]

## cos#

cos[x]


Cosine of x (given in radians).

Example:

cos[pi_float64] = -1.0

#### Definition#

@inlinedef cos[x] = rel_primitive_cos[x]

## acos#

acos[x]


Inverse cosine (in radians). Gives an error if ${\rm abs}[x] > 1$.

Example:

acos[0] = 1.5707963267948966

#### Definition#

@inlinedef acos[x] = rel_primitive_acos[x]

## tan#

tan[x]


Tangent of x (given in radians).

Example:

tan[pi_float64/4] = 0.9999999999999999

#### Definition#

@inlinedef tan[x] = rel_primitive_tan[x]

## atan#

atan[x]


#### Definition#

@inlinedef atan[x] = rel_primitive_atan[x]

## atan2#

atan2[y, x]


Inverse tangent returning an angle (in radians) between the positive x-axis and the ray to the point (x, y).

#### Definition#

@inlinedef atan2[x,y] = rel_primitive_atan2[x,y]

## cot#

cot[x]


Cotangent of x (given in radians).

#### Definition#

@inlinedef cot[x] = rel_primitive_cot[x]

## acot#

acot[x]


#### Definition#

@inlinedef acot[x] = rel_primitive_acot[x]

## sinh#

sinh[x]


Hyperbolic sine.

#### Definition#

@inlinedef sinh[x] = rel_primitive_sinh[x]

## cosh#

cosh[x]


Hyperbolic cosine.

#### Definition#

@inlinedef cosh[x] = rel_primitive_cosh[x]

## tanh#

tanh[x]


Hyperbolic tangent.

#### Definition#

@inlinedef tanh[x] = rel_primitive_tanh[x]

## asinh#

asinh[x]


Inverse hyperbolic sine.

#### Definition#

@inlinedef asinh[x] = rel_primitive_asinh[x]

## acosh#

acosh[x]


Inverse hyperbolic cosine.

#### Definition#

@inlinedef acosh[x] = rel_primitive_acosh[x]

## atanh#

atanh[x]


Inverse hyperbolic tangent.

#### Definition#

@inlinedef atanh[x] = rel_primitive_atanh[x]

deg2rad[x]


#### Definition#

@inlinedef deg2rad[x] = x * pi_float64 / 180.0

rad2deg[x]


#### Definition#

@inlinedef rad2deg[x] = x / pi_float64 * 180.0

## haversine#

haversine[r, x1, y1, x2, y2]


The great circle distance of two points, i.e $(x1,y1)$ and $(x2,y2)$, on a sphere of radius $r$, using the Haversine formula. The two points are specified by their latitude and longitude in radians.

Example:

def output = haversine[10, 0, 0, 0, pi_float64/2]15.707963267948964

#### Definition#

@inlinedef haversine[r, x1, y1, x2, y2] =    2 * r * asin[sqrt[sin[(x2 - x1)/2] ^ 2 + cos[x1] * cos[x2] * sin[(y2 - y1) / 2] ^ 2]]

## range#

range(low, hi, stride, x)


Generate a relation with integer values between low and high, inclusive, advancing by stride each time.

• If low <= hi and stride > 0, then range[low, hi, stride] returns all values x = low + i * stride <= hi for non-negative integers i.
• Otherwise (i.e. if low > hi or stride <= 0), then range[low, hi, stride] is empty.

Example:

def output = range[1, 10, 4]159

#### Definition#

@inlinedef range = rel_primitive_range

## eq#

eq(x, y)
x = y


Equality between scalar (single) values, such as integers, strings, symbols. (For equality between relations, use equal.)

Examples:

• 1 = 1 is true.
• :a = :a is true
• "a" = "a" is true
• 2 = 2.0 is false
• 1 = "a" is false

#### Definition#

@inlinedef eq(x, y) = rel_primitive_eq(x, y)@inlinedef (=)(x, y) = eq(x, y)

## neq#

neq(x, y)
x ≠ y
x != y


Examples:

• 1 != 2 is true
• 1 != 1.0 is true
• 1 != "a" is true

#### Definition#

@inlinedef neq(x, y) = rel_primitive_neq(x, y)@inlinedef (≠)(x, y) = neq(x, y)@inlinedef (!=)(x, y) = neq(x, y)

## lt#

lt(x, y) x < y

#### Definition#

@inlinedef lt(x, y) = rel_primitive_lt(x, y)@inlinedef (<)(x, y) = lt(x, y)

## gt#

gt(x, y) x > y

#### Definition#

@inlinedef gt(x, y) = rel_primitive_gt(x, y)@inlinedef (>)(x, y) = gt(x, y)

## lt_eq#

lt_eq(x, y) x ≤ y x <= y

#### Definition#

@inlinedef lt_eq(x, y) = rel_primitive_lt_eq(x, y)@inlinedef (≤)(x, y) = lt_eq(x, y)@inlinedef (<=)(x, y) = lt_eq(x, y)

## gt_eq#

gt_eq(x, y) x ≥ y x >= y

#### Definition#

@inlinedef gt_eq(x, y) = rel_primitive_gt_eq(x, y)@inlinedef (≥)(x, y) = gt_eq(x, y)@inlinedef (>=)(x, y) = gt_eq(x, y)

## equal#

equal(R, S)


Relational equality. Note that eq and = should be used only for scalar values, while equal should be used to check that two relations are the same.

#### Definition#

@inlinedef equal(R, S) = forall(x... where R(x...): S(x...)) and forall(x... where S(x...): R(x...))

## count#

count[R]


Number of tuples in R, if R is not empty. If R is empty, count[R] is false.

Examples:

• count[employee] returns the number of tuples in relation employee
• d in department: count[d.member] returns the member count for every department with at least 1 member
• count[5] returns 1 because 5 is a singleton relation
• count[{}] is false.

#### Definition#

@inlinedef count[R] = sum[{R,1}]

## sum#

sum[R]
Σ[R]


Sum of (the last argument of) the relation R, if non-empty. If R is empty, sum[R] is false.

Example:

def salary = {("John", 10) ; ("Mary", 20); ("Paul", 17) ; ("Peter", 15) }def output = sum[salary]62def member = {("A", "John"); ("B", "Mary") ; ("A", "Paul") ; ("C" , "Peter") }def department = {"A"; "B"; "C" }def output = d in department: sum[salary[p] for p in member[d]]("A", 27)("B", 20)("C", 15)

#### Definition#

@inlinedef sum[R] = rel_primitive_reduce_noinit[add, R]

## Σ#

sum[R]
Σ[R]


Sum of (the last argument of) the relation R, if non-empty. false if R is empty.

Example:

d in department: Σ[salary[p] for p in member[d]]

#### Definition#

@inlinedef Σ = sum

## sum_int#

sum_int[R]


Integer sum of (the last argument of) the relation R, which should be ints. sum_int[R] = 0 for empty R.

#### Definition#

@inlinedef sum_int[R] = rel_primitive_reduce[add, 0, R]

## product#

product[R]


Product of (the last argument of) the relation R, if non-empty. If R is empty, product[R] is false.

Example:

product[{(1, 4); (2, 5)}] = 20

#### Definition#

@inlinedef product[R] = rel_primitive_reduce_noinit[multiply, R]

## max#

max[R]


Maximum of (the last argument of) the relation R, if non-empty. If R is empty, max[R] is false.

Example:

max[{(2, 3); (1, 6)}] = 6

#### Definition#

@inlinedef max[R] = rel_primitive_reduce_noinit[maximum, R]

## Max#

Max[R]


Please use max[R]. Deprecates in near future

#### Definition#

@inlinedef Max = max

## min#

min[R]


Minimum of (the last argument of) the relation R, if non-empty. If R is empty, min[R] is false.

Example:

min[{(2, 3); (1, 6)}] = 3

#### Definition#

@inlinedef min[R] = rel_primitive_reduce_noinit[minimum, R]

## Min#

Min[R]


Please use min[R]. Deprecates in near future

#### Definition#

@inlinedef Min = min

## clamp#

clamp[lo, hi, v]


clamp limits the value v to a given range(lo, hi), changing values outside the range to the closest lo, hi value if necessary. The arguments should have the same type.

Examples:

clamp[2, 5, 1] = 2clamp[2, 5, 6] = 5clamp[2, 5, 3] = 3

#### Definition#

@inlinedef clamp[lo, hi, v] = min[{max[{lo; v}]; hi}]

## argmax#

argmax[R]


Find the keys for the largest value of the relation R.

Examples:

def output = argmax[{(2, 3); (1, 6)}]1def output = argmax[{(2, 6); (1, 6); (5, 0)}]12// find the teams with the largest aggregated salary:argmax[d in team: sum[salary[p] for p in member[d]]]

#### Definition#

@inlinedef argmax[R] = R.(max[R])

## ArgMax#

ArgMax[R]


Please use argmax[R]. Deprecates in near future

#### Definition#

@inlinedef ArgMax = argmax

## argmin#

argmin[R]


Find the keys for the smallest value of the relation R.

Examples:

def output = argmin[{(2, 3); (1, 6)}]2def output = argmin[{(2, 6); (1, 6); (5, 10)}]12// find the teams with the smallest aggregated salary:argmin[d in team: sum[salary[p] for p in member[d]]]

#### Definition#

@inlinedef argmin[R] = R.(min[R])

## ArgMin#

ArgMin[R]


Please use argmin[R]. Deprecates in near future

#### Definition#

@inlinedef ArgMin = argmin

## min_k#

min_k[K, R]


Returns the minimum K distinct values of (the last column of) the relation R, if non-empty. If R contains less than K distinct values (in its last column), then less than K values will be returned. If R is empty, min_k[K, R] is false. Currently, the maximum supported value of K is 10000.

min_k[2, {(2, 3); (1, 6); (3, 5); (1, 1); (4, 1); (2, 6)}]

returns {1; 3}.

#### Definition#

@inlinedef min_k[K, R] = rel_primitive_mink[R, K, 0]

## max_k#

max_k[K, R]


Returns the maximum K distinct values of (the last column of) the relation R, if non-empty. If R contains less than K distinct values (in its last column), then less than K values will be returned. If R is empty, max_k[K, R] is false. Currently, the maximum supported value of K is 10000.

max_k[2, {(2, 3); (1, 6); (3, 5); (1, 1); (4, 1); (2, 6)}]

returns {5; 6}.

#### Definition#

@inlinedef max_k[K, R] = rel_primitive_mink[R, K, 1]

## mean#

mean[R]
average[R]


The arithmetic mean of (the last argument of) the relation R, if non-empty. False if R is empty.

#### Definition#

@inlinedef mean[R] = sum[R] / count[R]

## average#

mean[R]
average[R]


The arithmetic mean of (the last argument of) the relation R, if non-empty. False if R is empty.

#### Definition#

@inlinedef average = mean

## geometric_mean#

geometric_mean[R]


The geometric mean of the values of a relation.

Example:

def output = geometric_mean[{('a',1); ('b',2); ('a',3); ('b',4); ('c',5); ('d',6}]2.99379516552

#### Definition#

@inlinedef geometric_mean[R] = power[product[R], 1 / count[R]]

## harmonic_mean#

harmonic_mean[R]


The harmonic mean of the values of a relation.

Example:

def output = harmonic_mean[{('a',1); ('b',2); ('a',3); ('b',4); ('c',5); ('d',6}]2.44897959184

#### Definition#

@inlinedef harmonic_mean[R] = count[R] / sum[a..., v, i: R(a..., v) and i = 1 / v]

## weighted_mean#

weighted_mean[R, W]


The weighted mean of values in relation R with weights defined by W. The last attribute of the relation representing the weights is used to compute the weighted mean. When the arity of the relation that represents the weights is different from the arity of the input relation the user is expected to align the arities before passing them to weighted_mean.(See examples 2 and 3)

Example 1 (The arity of both R and W are the same):

def inputs = {(1,'a',10); (2,'b',10); (3,'c',30); (4,'d',40); (5,'e',50)}def weights = {(1,'a',11); (2,'b',12); (3,'c',13); (4,'d',14); (5,'e',15)}def output = weighted_mean[inputs, weights]29.692307692307693

Example 2 (The arity of R and W are different):

def inputs = {(1,'a',10); (2,'b',10); (3,'c',30); (4,'d',40); (5,'e',50)}def weights = {(1,11); (2,12); (3,13); (4,14); (5,15)}def output = weighted_mean[inputs, (n: _, weights[n])]29.692307692307693

Example 3 (The arity of R and W are different):

def inputs = {(1,'a',100,10); (2,'a',200,10); (3,'b',300,30); (4,'c',400,40); (5,'b',500,50)}def weights = {(1,'a',11); (2,'a',12); (3,'b',13); (4,'c',14); (5,'b',15)}def output = weighted_mean[input, (n, c: _, weights[n,c])]29.692307692307693

#### Definition#

@inlinedef weighted_mean[R,W] = sum[k...: R[k...] * W[k...]] / sum[domain[R] <: W]

## frequency#

frequency(R, elem, c)
frequency[R, elem]
frequency[R]


Finds the frequency c of elem in (the last argument of) the relation R.

Example:

def example = {(1, "a"); (2, "b"); (3, 123); (4, 12.5); (3, "b")}def output = frequency[example, "b"]2def output = frequency[example]("a", 1)("b", 2)(123, 1)(12.5, 1)

#### Definition#

@inlinedef frequency[R, elem] = count[x...: R(x..., elem)]

## mode#

mode[R]


Finds the most common value in (the last argument of) the relation R. If there are multiple most common values, then mode chooses the first one according to the sort order.

Examples:

def example = {(1, "a"); (2, "b"); (3, 123); (4, 12.5); (3, "b")}mode[example] = "b"def example = {(1, 1); (2, 1); (3, 1); (4, "b"); (5, "b"); (6, "c"); (7, "c")}mode[example] = 1

#### Definition#

@inlinedef mode[R] = last[top[1, argmax[frequency[R]]]]

## squared#

squared[R]


Square of a relation: the value of each last element is squared.

Examples:

def example = {(1, 2); (3, 4)}equal(square[example], {(1, 4); (3, 16)}

#### Definition#

@inlinedef squared[F][x...] = F[x...] ^ 2

## squared_deviation#

squared_deviation[R]


Squared deviation: squared deviation from the mean of (the last argument of) the relation R.

#### Definition#

@inlinedef squared_deviation[F][x...] = (F[x...] - mean[F]) ^ 2

## pop_variance#

pop_variance[R]


Population variance

#### Definition#

@inlinedef pop_variance[F] = mean[squared_deviation[F]], count[F] > 1

## sample_variance#

sample_variance[R]


Sample variance

#### Definition#

@inlinedef sample_variance[F] = sum[squared_deviation[F]] / (count[F] - 1), count[F] > 1

## pop_standard_deviation#

pop_standard_deviation[R]
pop_stddev[R]


Population standard deviation

#### Definition#

@inlinedef pop_standard_deviation[F] = sqrt[pop_variance[F]]@inlinedef pop_stddev = pop_standard_deviation

## sample_standard_deviation#

sample_standard_deviation[R]
sample_stddev[R]


Sample standard deviation of (the last argument of) the relation R.

#### Definition#

@inlinedef sample_standard_deviation[F] = sqrt[sample_variance[F]]

## sample_stddev#

see: sample_standard_deviation

#### Definition#

@inlinedef sample_stddev = sample_standard_deviation

## min_max_normalization#

min_max_normalization[R]


Min-Max normalization: $x_n = (x_n - {\rm min}[R]) / {\rm max}[R] - {\rm min}[R]$.

Also known as min-max scaling or rescaling.

#### Definition#

@inlinedef min_max_normalization[R][x...] =    (R[x...] - min[R]) / (max[R] - min[R]), (max[R] > min[R])

## mean_normalization#

mean_normalization[R]


Mean normalization: $x_n = (x_n - {\rm mean}[R]) / {\rm max}[R] - {\rm min}[R]$

#### Definition#

@inlinedef mean_normalization[R][x...] =    (R[x...] - mean[R]) / (max[R] - min[R]), (max[R] > min[R])

## pop_zscore_normalization#

pop_zscore_normalization[R]


Z-score normalization (population) of (the last argument of) the relation R.

#### Definition#

@inlinedef pop_zscore_normalization[R][x...] =    (R[x...] - mean[R]) / pop_stddev[R]

## sample_zscore_normalization#

sample_zscore_normalization[R]


Z-score normalization (sample) of (the last argument of) the relation R.

Often simply referred to as ‘standardization’.

#### Definition#

@inlinedef sample_zscore_normalization[R][x...] = (R[x...] - mean[R]) / sample_stddev[R]

## unit_normalization#

unit_normalization[R]


Unit vector normalization: $x_n = x_n / ( Σ (x^2) ) ^ {0.5}$

#### Definition#

@inlinedef unit_normalization[R][x...] = R[x...] / sqrt[sum[squared[R]]]

## mse#

mse[YHAT, Y]


Mean squared error (MSE, L2)

#### Definition#

@inlinedef mse[YHAT, Y] = Σ[x... : (Y[x...] - YHAT[x...]) ^ 2] / count[Y]

## rmse#

rmse[YHAT, Y]


Root mean square error (RMSE)

#### Definition#

@inlinedef rmse[YHAT,Y] = sqrt[mse[YHAT,Y]]

## mae#

mae[YHAT, Y]


Mean absolute error (MAE, L1)

#### Definition#

@inlinedef mae[YHAT,Y] = mean[x... : abs[Y[x...] - YHAT[x...]]]

## sort#

sort[R]


Sort a relation.

sort takes a relation R(xs...) and produces a relation R(i, xs...) where i is an Int64 index starting at 1. The index indicates the ordering of the tuples of R.

The ordering is the native sort order of values in the system and cannot be customized with a comparator. It is possible though to transform the input or output of sort to achieve a different sort order (see reverse_sort for an example).

Example:

def sample = 'a'def output = sort[sample](1, 'a')def sample = {'a'; 'b'; 'c'}def output = sort[sample](1, 'a')(2, 'b')(3, 'c')

Similar to aggregations, it is possible to separately sort per group. In the following example, the sort is grouped by free variable g.

def sample = {(:g, 'a'); (:g, 'b'); (:g, 'c'); (:h, 'd'); (:h, 'e'); (:h, 'f')}def output = x: sort[sample[x]](:g, 1, 'a')(:g, 2, 'b')(:g, 3, 'c')(:h, 1, 'd')(:h, 2, 'e')(:h, 3, 'f')

#### Definition#

@inlinedef sort = rel_primitive_sort

## reverse_sort#

reverse_sort[R]


Reverse Sort

Like sort, except the ordering is reversed.

Example:

def sample = {'a'; 'b'; 'c'}def output = reverse_sort[sample](1, 'c')(2, 'b')(3, 'a')def sample = {(:g, 'a'); (:g, 'b'); (:g, 'c'); (:h, 'd'); (:h, 'e'); (:h, 'f')}def output = x: reverse_sort[sample[x]](:g, 1, 'c')(:g, 2, 'b')(:g, 3, 'a')(:h, 1, 'f')(:h, 2, 'e')(:h, 3, 'd')

#### Definition#

@inlinedef reverse_sort[R](ri, args...) =    sort[R](i, args...) and    ri = count[R] - i + 1    from i

## docstring#

docstring[:R]


Return the docstring of a relation as a string.

Example:

doc"Returns 0." def zero = 0def output = docstring[:zero]"Returns 0."

#### Definition#

@inlinedef docstring = rel_primitive_docstring

## auto_number#

auto_number[R]


AutoNumber a relation.

auto_number takes a relation R(xs...) and produces a relation R(xs..., i) where i is a distinct AutoNumberValue index.

Note that auto_number can give different results each time it is called.

Example:

def sample = 'a'def output = auto_number[sample]('a', AutoNumberValue(0x12))def sample = {'a'; 'b'; 'c'}def output = auto_number[sample]('a', AutoNumberValue(0x132))('b', AutoNumberValue(0x133))('c', AutoNumberValue(0x134))

#### Definition#

@inlinedef auto_number = rel_primitive_auto_number

## hash128#

hash128[R]


Hash128 each of the tuples in a relation.

hash128 takes a relation R(xs...) and produces a relation R(xs..., i) where i is a HashValue index. The index indicates the hash128 of each tuple of R.

Example:

def output = hash128['a']('a', HashValue(0xbd1defa3be4617e0))def sample = {'a'; 'b'; 'c'}def output = hash128[sample]('a', HashValue(0xbd1defa3be4617e0))('b', HashValue(0x2423a34d925fc9ed))('c', HashValue(0xd2cffd2ea6c73a7))

#### Definition#

@inlinedef hash128 = rel_primitive_hash

## hash#

hash[R]


see hash128

#### Definition#

@inlinedef hash = hash128

## uint128_hash_value_convert#

uint128_hash_value_convert[v]


Convert a provided UInt128 value v to the HashValue type. This is an internal-facing function, used for the implementation of hashing.

#### Definition#

@inlinedef uint128_hash_value_convert[v] = rel_primitive_uint128_hash_value_convert[v]

## murmurhash3f_with_seed#

murmurhash3f_with_seed[seed in (Int64 ∪ UInt128), key]


Hash key with seed via the MurmurHash3F algorithm, and yield the result as a UInt128.

The key may be any singleton value supported in Rel, (e.g. [U]Int{8,16,32,64,128}, Float{16,32,64}, Char, String, RelName, FilePos, Missing, …).

The seed must be a value in (Int64 ∪ UInt128).

Note that the standard specification for MurmurHash3F does not include 128-bit seeds, so the result of hashing with a 128-bit seed will be different than a hash with the same value stored in a smaller integer type (i.e. hashing with the seeds uint64[1] and uint128[1] will result in different hashes).

This function is an implementation (in Julia) of the reference implementation of MurmurHash3F, i.e. MurmurHash3_x64_128. The original can be retrieved via:

https://github.com/aappleby/smhasher/blob/ 61a0530f28277f2e850bfc39600ce61d02b518de/src/MurmurHash3.cpp

The reference implementation was written by Austin Appleby and made public domain.

Note that this implementation departs from the standard, in order to provide different hashes for byte-identical values of different types. While this implementation’s internals should produce byte-identical results to the reference implementation, the primary entrypoint here, (murmurhash3f[seed, key]) typically will not: To distinguish byte-identical values of different types, this function mixes type information into seeds prior to hashing.

Also note that the reference implementation supports only UInt32 seeds; for such seeds, this implementation’s internals should provide byte-identical results. But this implementation accepts seeds up to and including 128-bit integer types. (For UInt32 seeds, the reference implementation initializes h1/h2, the two UInt64s in which it accumulates/mixes the digest, with copies of seed. This implementation does the same for UInt32 seeds, and also for all other seed types <= 64 bits. For 128-bit seeds, this implementation initializes h1 with the seed’s low bits and h2 with the seed’s high bits.)

Examples

// Without a seedmurmurhash3f["cat"] = 0x670c9caac40b25a8f2bd407bd1ddbec7// With a seedmurmurhash3f[8675309, "cat"] = 0xdbde75f53ecda9e37734271e899eaf87murmurhash3f[8675309, :bunny] = 0x32822e3f70a1d87e5f86fea6c763b67f// byte-identival values of different types hash differentlymurmurhash3f[0x01] = 0x6ed3439777f613f7df39df0849d45e09murmurhash3f[1] = 0x9116cd3f0a651c49f1674100935b29bf

#### Definition#

@inlinedef murmurhash3f_with_seed[seed, v] = rel_primitive_murmurhash3f_with_seed[seed, v]

## murmurhash3f#

murmurhash3f[v]


Hash v according to the MurmurHash3f algorithm with the default seed 0, returning the result as a UInt128.

Equivalent to murmurhash3f_with_seed[0, v].

#### Definition#

@inlinedef murmurhash3f[v] = murmurhash3f_with_seed[int64[0], v]

## top#

top[k, R]


Select the top k facts of relation R according to the sort order of R.

top is sort restricted to first k tuples. top takes a relation R(xs...) and produces a relation R(i, xs...) where i is an Int64 index starting at 1. The index indicates the ordering of the tuples of R.

If k is bigger than number of tuples in the relation, then only the sorted relation itself is returned. This means that the cardinality of the result is the minimum of k and the cardinality of R.

Example:

def output = top[2, {'a'; 'b'; 'c'; 'd'}](1, 'a')(2, 'b')

Note: Currently top[k, R] only supports groupbys in the R-expression but not in the k-expression. For example, the following is supported:

def output[g] = top[K, R[g]]  // g here is a groupby for R

However the following is NOT supported:

def output[g] = top[K[g], R]  // g here is a groupby for K

#### Definition#

@inlinedef top[K, R] = rel_primitive_top[R, K]

## bottom#

bottom[k, R]


Select the bottom k facts of relation R according to the sort order of R.

bottom is reverse_sort (which sorts highest to lowest) restricted to the first k facts.

Example:

def output =  bottom[2, {'a'; 'b'; 'c'; 'd'}](1, 'd')(2, 'c')

#### Definition#

@inlinedef bottom[k, R] =    reverse_sort[R][i] for i where i <= k

## percentile_nearest#

percentile_nearest[R, p]


Select the element of R corresponding to the p-th percentile.

The p-th percentile is the smallest value in the list such that no more than p percent of the data is strictly less than the value and at least p percent of the data is less than or equal to that value (nearest-rank method in https://en.wikipedia.org/wiki/Percentile). This function computes the p-th percentile based on ranking the last argument of R.

Note that percentile_nearest is not defined for p <= 0 or p > 100.

Example, here 33% of the values are strictly less than 16, and 66% of the values are less than or equal to 16, so the 60-th percentile is 16:

def output = percentile_nearest[{(1, 12); (2, 24); (3, 16)}, 60]16

#### Definition#

@inlinedef percentile_nearest[R, p] =    // we need to sort[y, x...] instead of sort[last[R]] to handle duplicates properly    first[(sort[y, x...: R(x..., y)][i] from i        where i = float_int_convert[ceil[(p / 100.0) * count[R]]])]

## percentile#

percentile[R, p]


Select the element of R corresponding to the p-th percentile, computed with linear interpolation.

If the p-th percentile does not correspond to a single element, then percentile_continuous computes a weighted average of the two values surrounding the p-th percentile.

There are a number of different approaches for computing linearly interpolated percentiles. Here, the rank of the percentile is computed by x = p(N - 1) + 1, which corresponds to the C = 1 variant in https://en.wikipedia.org/wiki/Percentile. This is also the approach used in Julia’s libraries and NumPy.

Note that percentile is not defined for p <= 0 or p > 100.

Example:

def output = percentile[{(1, 12); (2, 24); (3, 16)}, 60]17.6

#### Definition#

@inlinedef percentile[R, p] = value :    // index is a float value, we multiply by count[R] - 1 first rather than divide by    // 100.0 first to avoid imprecision    index = (p * (count[R] - 1.0)) / 100.0 + 1.0 and    // compute the lower and upper bounds surrounding the value for the p-th percentile    value = sum[i, s:        // the value at index i contributes (1 - abs[i - index]) proportion of the final        // percentile        s = v * (1 - abs[i - index]) and        // sort[y, x...] instead of sort[last[R]] to handle duplicate values        sort[y, x...: R(x..., y)](i, v, rest...) and        // only for the values surrounding index        index - 1.0 <= 1.0 * i <= index + 1.0        from v, rest...    ]    from index

## median#

median[R]


Returns the median of R according to the sort order of the last element. If the median index is between two values, then median takes the mean of the middle two values.

Example:

def output = median[{(1, 12); (2, 16); (3, 24)}]16

#### Definition#

@inlinedef median[R] = percentile[R, 50]

## describe#

describe[R]


Gives a summary of statistics for a dataset R. R should be a relation given in the form R(:feature_name, keys..., value). For example, data loaded using load_csv.

For each feature in the dataset, describe computes a set of statistics depending on the data type of that feature.

For numerical data, describe computes the count, mean, standard deviation, minimum, 25th, 50th, 75th percentiles, and maximum for that feature.

For non-numerical data, describe computes the count, unique count, mode, and mode frequency. It will also compute maximum and minimum values if the data is sortable.

If a dataset has multiple data types, it will print the numerical stats for the numerical subset, and non-numerical stats for the non-numerical subset of the data.

For example, given a dataset R in the form (produced by the CSV loader):

R = {(:date, FilePos(29), 2020-01-01);(:date, FilePos(60), 2020-02-02);(:date, FilePos(91), 2020-03-03);(:date, FilePos(127), 2020-04-04);(:price, FilePos(29), 12.5);(:price, FilePos(60), 14.25);(:price, FilePos(91), 11.0);(:price, FilePos(127), 12.25);(:quantity, FilePos(29), 2);(:quantity, FilePos(60), 4);(:quantity, FilePos(91), 4);(:quantity, FilePos(127), 3);(:cocktail, FilePos(29), "martini");(:cocktail, FilePos(60), "sazerac");(:cocktail, FilePos(91), "cosmopolitan");(:cocktail, FilePos(127), "bellini");}

describe will compute a summary:

Example:

def d = describe[R]d[:date](:mode, Dates.Date("2020-01-01"))(:count, 4)(:mode_freq, 1)(:min, Dates.Date("2020-01-01"))(:max, Dates.Date("2020-04-04"))(:unique, 4)d[:quantity](:max, 4)(:count, 4)(:std, 0.9574271077563381)(:min, 2)(:percentile75, 4.0)(:percentile25, 2.75)(:percentile50, 3.5)(:mean, 3.25)

A describe_full method is also provided, which does not aggregate over columns, and instead computes the statistics for the whole dataset. However, describe_full may cause errors if any unsortable data (e.g., symbols) exists in the relation.

For example, given the relation R defined above:

Example:

describe_full[R](:min, 32)(:unique, 3)(:mode, "a")(:std, 49.47186262580647)(:percentile25, 89.2175)(:min, 3.27)(:percentile50, 53.6)(:mean, 16.75)(:mean, 18.8675)(:count, 7)(:max, 72.2)(:max, 35)(:mode_freq, 1)

#### Definition#

@inlinedef describe[R] = column: describe_full[R[column]]// Stats for all types@inline def describe_full[R, :count] = count[R]@inline def describe_full[R, :min] = min[R]@inline def describe_full[R, :max] = max[R]// Stats for non-numeric types@inline def describe_full[R, :unique] = count[last[R :> (x: not Number(x))]]@inline def describe_full[R, :mode] = mode[R :> (x: not Number(x))]@inline def describe_full[R, :mode_freq] = max[frequency[R :> (x: not Number(x))]]// Stats for numeric types@inline def describe_full[R, :mean] = mean[R :> Number]@inline def describe_full[R, :std] = sample_stddev[R :> Number]@inline def describe_full[R, :percentile25] = percentile[(R :> Number), 25]@inline def describe_full[R, :percentile50] = median[R :> Number]@inline def describe_full[R, :percentile75] = percentile[(R :> Number), 75]

load_csv[URI_string]


This is the main in-language API for loading CSV data. To load a CSV, either provide the string URI where the data resides, or a configuration relation R that describes the data load.

In the first case, all columns are imported with type String.

The relation R, which must be an EDB or an IDB but not a formula, can configure the data load with the following options:

Required: Either

• :path: The path to the CSV file, e.g. "azure://storage.blob.core.net/container/file.csv" Or
• :data: A CSV formatted string value

Optional:

• :schema: A relation containing schema information.
• :syntax: A relation containing syntax configuration.
• :integration: A relation containing storage integration configuration.

The resulting relation is of the form (column_name, file_position, value). The file_position uniquely identifies each row in the CSV.

Examples:

def config[:data] = "A,B,C\n1,2,3"def csv = load_csv[config]

def y = load_csv["test.csv"]def x = y[:A, _]

In the example above, all values for column :A (symbolized from “A” in the original file) are stored in x.

This can also be used to only load specific columns: load_csv[path](:A, xs...).

Loading a CSV file using a configuration relation R:

def config[:path] = "/path/to/file.csv"def config[:syntax, :delim] = '_'def config[:syntax, :header] = (1, :A); (2, :B); (3, :C)def config[:schema, :A] = "int"def config[:schema, :B] = "string"def config[:schema, :C] = "decimal(64,2)"def csv = load_csv[config]

Lastly, load_csv also supports error handling. If the CSV can’t be read (e.g. if it is badly formatted), parsing errors are stored in the :load_errors “column”, which can be accessed the same way as any other column. It has the format (:load_errors, file_position, error_column, raw_line). Note : Since the arities of regular columns and the error relations differ, use the splat operator ("…") to make your program as resilient as possible (cf. examples above).

#### Definition#

@inlinedef load_csv = rel_primitive_load_csv

load_csv_row_wise[R]


Load a CSV file into a “row-wise” relation, with the position as the first argument, and the column name second. Included for backwards-compatiblity, we now recommend using load_csv instead, which puts the column name first.

#### Definition#

@inlinedef load_csv_row_wise[R][pos, col] = rel_primitive_load_csv[R][col, pos]

## lined_csv#

lined_csv[R]


Given an already loaded CSV relation, returns a copy of the relation, but with the file position field replaced with a line number. Only lines containing data, including errors, are included in the numbering. Headers and empty lines are not counted. Thus, line number 1 is the first non-empty, non-header line of the CSV relation.

Example:

def csv = load_csv[config]def csv_with_lines = lined_csv[csv]

#### Definition#

@inlinedef lined_csv[R](col, line, rest...) = sort[second[R]](line, pos) and R(col, pos, rest...) from pos

## export_csv#

export_csv[R]


This is the main entry point to specify relations that should be exported to CSV. The payload relation R is expected to be a configuration relation mapping keys to relations.

Required keywords are:

• :path: A string specifying the location of the file that is to be created.

Optional keywords:

• :data: A set of relations mapping a file position, which can be a key of arbitrary length or type, to the corresponding value. This is the data that will be exported. We expect the data relation to be of form: data(pos…, :COLUMN_NAME, val)
• :integration: A relation containing storage integration configuration.
• :schema: A relation containing schema information.
• :syntax: A relation containing syntax configuration.

Example using default CSV schema and syntax and no storage integration.

def csv_data(:ORDER, pos, v) = ((1,1); (2,2); (3,3))(pos, v)def csv_data(:LINEITEM, pos, v) = ((1,100); (2,101); (3,102))(pos, v)def csv_data(:QUANTITY, pos, v) = ((1,2); (2,15); (3,42))(pos, v)def export = export_csv[(:path, "/path/to/local/file.csv"); (:data, csv_data)]

Example using a custom CSV schema.

def csv_syntax[:delim] = ';'def csv_syntax[:quotechar] = '_'def export = export_csv[(:path, "/path/to/local/file.csv");                        (:data, csv_data);                        (:syntax, csv_syntax)]

Example using an Azure storage integration using a SAS token:

def integration[:provider] = "azure"def integration[:credentials, :azure_sas_token] = "<azure_sas_token>"def export = export_csv[(:path, "azure://<account_name>.blob.core.windows.net/container/file.csv");                        (:data, csv_data);                        (:integration, integration)]

Example with compound keys:

def csv_data(:ORDER, pos..., v) = (1, 2, 100; 2, 1, 40)(pos..., v)def csv_data(:QUANTITY, pos..., v) = (1, 3, 10; 2, 3, 11; 3, 1, 12; 3, 2 ,13)(pos..., v)def export = export_csv[(:data, csv_data; :path, "/path/to/data.csv")]

#### Definition#

@inlinedef export_csv[R](ys..., xs...) = (:envelope, (:payload, (        (:data, ((key..., col, val): R[:data](col, key..., val))) ; (x, y...: R(x, y...), (x != :data))    )(xs...); (:content_type, "text/csv")(xs...)))(ys...)@inlinedef export_csv_row_wise[R](ys..., xs...) = (:envelope, (:payload, R(xs...); (:content_type, "text/csv")(xs...)))(ys...)

    load_json[filename_or_url]


The relation R, which currently needs to either be an EDB or an IDB but no formula, can be used to configure the data load with the following options:

Required: Either

• :path: The path to the JSON file, e.g. "azure://storage.blob.core.net/container/file.json" Or
• :data: A JSON formatted string value

Optional:

• :integration: A relation containing storage integration configuration.

Examples:

def data = "{\\"name\\": \\"Anton\\", \\"age\\": 56}"def config[:data] = datadef json = load_json[config]

def y = load_json["test.json"]

def config[:path] = "/path/to/file.json"def json = load_json[config]

Loading a JSON file from behind a private Azure container using a SAS token:

def config[:path] = "azure://<account_name>.blob.core.windows.net/container/file.json"def config[:integration, :provider] = "azure"def config[:integration, :credentials, :azure_sas_token] = "<azure_sas_token>"def json = load_json[config]

#### Definition#

@inlinedef load_json = rel_primitive_load_json

## parse_json#

    parse_json[json_string_value]


Parses a JSON value directly from a string.

Example:

def json = parse_json[\"\"\"{"name": "Anton", "age": 56}\"\"\"]

#### Definition#

@inlinedef parse_json = rel_primitive_parse_json

## json_string#

    json_string[json_relation]


Returns the string representation of a relation encoding JSON data.

Example:

def json_relation[:name] = "Amira"def json_relation[:age] = 32def json_relation[:height] = missingdef json_relation[:pets, :[], 1] = "dog"def json_relation[:pets, :[], 2] = "rabbit"def result = json_string[json_relation]

results in the following JSON:

{
"name": "Amira",
"age": 32,
"height": null,
"pets": [
"dog",
"rabbit"
]
}


#### Definition#

@inlinedef json_string = rel_primitive_json_string

## export_json#

export_json[R]


This is the main entry point to specify relations that should be exported to JSON. The payload relation R is expected to be a configuration relation mapping keys to relations.

Required keywords are:

• :path: A string specifying the location of the file that is to be created.

Optional keywords:

• :data: The relation(s) that should be exported.
• :integration: A relation containing storage integration configuration.
• :indent: Number of spaces to indent the resulting document. If not present, we’ll write a compact form.

Example for a simple JSON object

def json[:author] = "David Foster Wallace"def json[:title, :name] = "Infinite Jest"def json[:title, :isbn] =  "978-0-316-92004-9"def export = export_json[(:path, "/path/to/file.json");                         (:data, json);                         (:indent, 2)]

This results in the following JSON:

{
"author": "David Foster Wallace",
"title": {
"name": "Infinite Jest",
"isbn": "10: 0316921173"
}
}


Since authors usually write more than one book, we’ll make the :title path an array of objects.

Examples:

def json[:author] = "David Foster Wallace"def titles = (1, "Infinite Jest", "978-0-316-92004-9");             (2, "The Pale King", "978-0-316-07423-0")def json[:titles, :[], idx] = ((:name, name);                               (:isbn, isbn)                               from name, isbn where titles(idx, name, isbn))def export = export_json[(:path, "/path/to/file.json");                         (:data, json);                         (:indent, 2)]

The :[] marker, i.e. array marker, needs to be present when an array is to be correctly produced.

This yields the following output:

{
"author": "David Foster Wallace",
"titles": [
{
"name": "Infinite Jest",
"isbn": "978-0-316-92004-9"
},
{
"name": "The Pale King",
"isbn": "978-0-316-07423-0"
}
]
}


#### Definition#

@inlinedef export_json[R](ys..., xs...) =    (:envelope, (        (:payload, R(xs...));        (:content_type, "application/json")(xs...)    ))(ys...)

## substring#

substring[string, index1, index2]


Substring of a string, selecting characters in range [index1:index2] (both inclusive).

The index of the first character is 1.

The supplied indexes are character indexes, corresponding to the char[s, i] function.

Example:

substring["abcd", 2, 3] = "bc"substring["中文例子", 2, 3] = "文例"

#### Definition#

@inlinedef substring = rel_primitive_substring

## string_replace#

string_replace[string, old_str, new_str]


Replace a string or character in string with the specific string or character.

Examples:

string_replace["One Two Three", "One", "1"] = "1 Two Three"string_replace["Rel", 'R', 'r'] = "rel"

#### Definition#

@inlinedef string_replace = rel_primitive_replace

## string_replace_multiple#

string_replace_multiple[input, R]


Replaces all occurrences of old string in input with the corresponding new string, for each tuple (old, new) in relation R.

Examples:

string_replace_multiple["One Two Three", {("One", "1"),("Two", "2")}] = "1 2 Three"string_replace_multiple["One Two Three", {('O', 'o'),('T', 't')}] = "one two three"

The behavior is undefined if new generates more occurrences of old.

#### Definition#

@inlinedef string_replace_multiple[input, R] = rel_primitive_reduce[(x,y,z: z=string_replace[x,y,R[y]]), input, (x: R(x,_))]

## string_trim#

string_trim[s]


To remove leading and tailing whitespaces in given string s

Example:

string_trim["  Good Day!!!  "] = "Good Day!!!"

@inlinedef string_trim[s] = string_replace[s, regex_compile["^\\s+|\\s+$"], ""] ## regex_match# regex_match(regex_string, string)  Match string with a regular expression Note that if the entire string needs to be matched, then a leading ^ and trailing$ is required.

Example:

#### Definition#

@inlinedef regex_compile = rel_primitive_regex_compile

## pattern_match#

pattern_match(pattern, string)


Match string with a pattern (pre-compiled regular expression)

Example:

def p = regex_compile["^.*@.*\$"]def output = pattern_match(p, "foo@example.com")true

#### Definition#

@inlinedef pattern_match = rel_primitive_pattern_match

## parse_int#

parse_int[string]


Parse a string representation of an integer to a SignedInt[64]

Derives to false if the string fails to parse as an integer.

Example:

parse_int["123"] = 123empty(parse_int["hello"])

#### Definition#

@inlinedef parse_int = rel_primitive_parse_int

## parse_float#

parse_float[string]


Parse a string representation of a float to a Floating[64]

Note that this currently does not consider a locale (decimal separator is always .)

Derives to false if the string fails to parse as an integer.

Examples:

parse_float["3.14"] = 3.14parse_float["3"] = 3.0empty(parse_int["hello"])

#### Definition#

@inlinedef parse_float = rel_primitive_parse_float

## parse_decimal#

parse_decimal[bits, digits, string]


Parse a string representation of a fixed-point decimal number to a decimal[a,b]

The implementation does not consider a locale. The decimal separator is always . and the thousands separator is always ,. The thousands separator is optional.

If the string has more digits after the decimal point than supported by the b parameter, then the number is rounded to the nearest number.

This function is only defined for valid arguments, and invalid arguments will return false (the empty relation, {}).

Examples:

parse_decimal[64, 2, "3.14"]FixedDecimal{Int64,2}(3.14)parse_decimal[64, 1, "4.27"]FixedDecimal{Int64,1}(4.3)parse_decimal[64, 2, ""]FixedDecimal{Int64,2}(0.00)parse_decimal[64, 2, "1,234.567"]FixedDecimal{Int64,2}(1234.57)parse_decimal[64, 2, "invalid"]{}

#### Definition#

@inlinedef parse_decimal = rel_primitive_parse_decimal

## decimal_bit_length#

decimal_bit_length[decimal]


Returns the bit length of a fixed-point decimal number.

Example:

def g = parse_decimal[64, 2, "3.14"]decimal_bit_length[g] = 64

#### Definition#

@inlinedef decimal_bit_length(x, y) = rel_primitive_decimal_type(x, y, _)

## decimal_precision#

decimal_precision[decimal]


Returns the precision of a fixed-point decimal number.

Example:

def g = parse_decimal[64, 2, "3.14"]decimal_precision[g] = 2

#### Definition#

@inlinedef decimal_precision(x, y) = rel_primitive_decimal_type(x, _, y)

## parse_uuid#

parse_uuid[str]


Parse a UUID string (in the standard 8-4-4-4-12 format) to a UInt128 value.

Example:

parse_uuid["22b4a8a1-e548-4eeb-9270-60426d66a48e"] = 0x22b4a8a1e5484eeb927060426d66a48e

#### Definition#

@inlinedef parse_uuid = rel_primitive_parse_uuid

## uuid_string#

uuid_string[v]


Convert a UInt128 value to the standard UUID format

Example:

uuid_string[0x22b4a8a1e5484eeb927060426d66a48e] = "22b4a8a1-e548-4eeb-9270-60426d66a48e"

#### Definition#

@inlinedef uuid_string = rel_primitive_uuid_string

## concat#

concat[str_or_char1, str_or_char2]


String concatenation between strings and/or characters.

Example:

concat["a", "b"] = "ab"concat["a", 'b'] = "ab"concat['a', "b"] = "ab"concat['a', 'b'] = "ab"

#### Definition#

@inlinedef concat = rel_primitive_concat

## string_length#

string_length[string]


DEPRECATED
This function is deprecated. Please prefer num_chars[string] or num_bytes[string], depending on your need.

Example:

string_length["foo"] = 3

#### Definition#

@inlinedef string_length = num_chars

## uppercase#

uppercase[string1]


Convert all characters to uppercase.

Example:

def output = uppercase["aB1c"]"AB1C"

lowercase does not take a locale option and does not handle local-specific case mapping rules.

#### Definition#

@inlinedef uppercase = rel_primitive_uppercase

## lowercase#

lowercase[string1]


Convert all characters to lowercase.

Example:

lowercase["aB1c"]"ab1c"

lowercase does not take a locale option and does not handle local-specific case mapping rules.

#### Definition#

@inlinedef lowercase = rel_primitive_lowercase

## levenshtein#

levenshtein[string1, string2]


Calculate the Levenshtein distance between two strings.

Example:

levenshtein["kitten", "sitting"]3

#### Definition#

@inlinedef levenshtein = rel_primitive_levenshtein

## num_chars#

num_chars[str]


Returns the number of (Unicode) characters in a string, i.e. the length of the string.

A character is also known as a “Code Point” in the Unicode specification.

Example:

num_chars["abcd"] = 4num_chars["中文例子"] = 4

#### Definition#

@inlinedef num_chars = rel_primitive_num_chars

## char#

char[str]
char[str, i]
char(str, i, c)


Indexes into a string at (Int) position i, returning the i-th character, c.

Since this is indexed using character positions, the returned character will always be a whole Unicode character.

A character is also known as a “Code Point” in the Unicode specification.

Both i and c can be optionally bound externally. When only str is bound, this returns the mapping from each character index to its corresponding character.

Examples

Indexing into a known character index:

char["abcd", 2] = 'b'char["中文例子", 2] = '文'

Abstracting over the character index:

equal(char["中文"],        { 1, "中"; 2, "文" })equal((i : char["awesome", i]('e')), {3; 7})

#### Definition#

@inlinedef char[s](i, c) =    rel_primitive_char(s, i, c) and range[1, num_chars[s], 1](i)

## num_bytes#

num_bytes[str]


Returns the number of bytes in a string value.

If a string contains Unicode characters, it’s possible that some characters take up more than one byte, so num_bytes[str] may be larger than num_chars[str].

Example:

num_bytes["abcd"] = 4num_bytes["中文例子"] = 12

#### Definition#

@inlinedef num_bytes = rel_primitive_num_bytes

## byte#

byte[str]
byte[str, i]
byte(str, i, b)


Indexes into a string at byte position i, returning the byte b as a UInt8 value.

If a string contains Unicode characters, it’s possible that a byte at index i might be only a partial character. Take care with your indexing logic.

Both i and b can be optionally bound externally. When only str is bound, this returns the mapping from each index to its corresponding byte.

Examples: Indexing into a known byte index:

byte["abcd", 2] = 0x62byte["中文例子", 2] = 0xb8

Abstracting over the byte index:

equal(byte["中文"],        { 1, 0xe4;          2, 0xb8;          3, 0xad;          4, 0xe6;          5, 0x96;          6, 0x87; })equal((i : byte["awesome", i](0x65)), {3; 7})

#### Definition#

@inlinedef byte[s](i, b) =    rel_primitive_byte(s, i, b) and range[1, num_bytes[s], 1](i)

## string#

string[x]


Convert ints, floats, dates, periods, to strings:

Examples:

string[1] = "1"string[3.4] = "3.4"string[unix_epoch] = "1970-01-01T00:00:00"string[Hour[1]] = "1 hour"string["a"] = "a"string[:a] = "a"

#### Definition#

@inlinedef string = rel_primitive_string

## string_join#

string_join[separator, R]


Concatenate together all the String values in the second argument of the binary relation R, if non-empty, separated by the separator string, following the ordering provided by the Ints in the first argument of R. If R is empty, string_join[sep, R] is false.

R is required to be a binary relation, containing only (Int, String) tuples, where the Int serves as the sort key for the concatenation. Otherwise, string_join[sep, R] is false. (Note: this restriction may be lifted in the future.)

Example:

string_join[", ", {(1, "a"); (2, "b"); (3, "c")}] = "a, b, c"string_join[" ", {(1, "hello"); (2, "world")}] = "hello world"string_join["->", sort[{"x"; "y"; "z"}]] = "x->y->z"

#### Definition#

@inlinedef string_join[sep, R] =    rel_primitive_reduce_noinit[_str_join2[sep], R],    // R is required to be a Binary relation with numeric keys to provide an ordering    R ⊆ (Int, String)// This helper function is reduced over the values in R, with the provided separator.@inlinedef _str_join2[sep, a,b] = concat[concat[a, sep], b]

## parse_date#

parse_date[d, format]


Parse Date

Examples:

def output = parse_date["2018-06-12", "Y-m-d"]2018-06-12

For details on the format parameter, see the Julia documentation for Dates.DateFormat.

#### Definition#

@inlinedef parse_date = rel_primitive_parse_date

## parse_datetime#

parse_datetime[dt, format]


Parse DateTime

Examples:

def output = parse_datetime["2018-06-12 13:00 +00:00", "YYYY-mm-dd HH:MM zzzz"]Dates.DateTime("2018-06-12T13:00:00")def output = parse_datetime["2018-03-11 01:00 America/New_York", "Y-m-d H:M Z"]Dates.DateTime("2018-03-11T06:00:00")

For details on the format parameter, see the Julia documentation for Dates.DateFormat.

#### Definition#

@inlinedef parse_datetime = rel_primitive_parse_datetime

## format_date#

format_date[d, format]


Format a Date d, returning a string.

Example:

def d = parse_date["2018-06-12", "Y-m-d"]def output = format_date[d, "Y-mm-d"]"2018-06-12"

For details on the format parameter, see the Julia documentation for Dates.DateFormat.

#### Definition#

@inlinedef format_date = rel_primitive_format_date

## format_datetime#

format_datetime[dt, format, tz]


Format a DateTime dt, with timezone tz.

Example:

def format = "yyyy-mm-dd HH:MM ZZZ"def dt = parse_datetime["2018-03-11 01:00 America/New_York", "Y-m-d H:M Z"]def output = format_datetime[dt, format, "America/New_York"]"2018-03-11 01:00 EST"

For details on the format parameter, see the Julia documentation for Dates.DateFormat.

#### Definition#

@inlinedef format_datetime = rel_primitive_format_datetime

## date_year#

date_year[d]


Year of a Date, as an integer.

Example:

date_year[parse_date["2020-05-22", "Y-m-d"]]2020Year[date_year[parse_date["2020-05-22", "Y-m-d"]]](2020 years,)

#### Definition#

@inlinedef date_year = rel_primitive_date_year

## datetime_year#

datetime_year[dt, tz]


Year of a DateTime dt, as an Int. Note that DateTime properties require a timezone tz.

Examples:

def dt = parse_datetime["2021-01-01 01:00:00", "Y-m-d H:M:S"]datetime_year[dt, "Europe/Berlin"] = 2021datetime_year[dt, "America/New_York"] = 2020datetime_year[dt, "-03:00"] = 2020

#### Definition#

@inlinedef datetime_year = rel_primitive_datetime_year

## date_month#

date_month[d]


Month of a Date, as an integer between 1 and 12.

#### Definition#

@inlinedef date_month = rel_primitive_date_month

## datetime_month#

datetime_month[dt, tz]


Month of a DateTime, as an integer between 1 and 12.

Note that DateTime properties require a timezone tz.

Examples:

def dt = parse_datetime["2021-01-01 01:00:00", "Y-m-d H:M:S"]datetime_month[dt, "Europe/Berlin"] = 1datetime_month[dt, "America/New_York"] = 12datetime_month[dt, "-03:00"] = 12

#### Definition#

@inlinedef datetime_month = rel_primitive_datetime_month

## date_week#

date_week[d]


Week of the year for a Date, as an integer, where the first week is the week that contains the first Thursday of the year. Ranges between 1 and 53, inclusive.

Example:

week[parse_date["2005-01-01", "Y-m-d"]] = 53 // 53rd week of 2004.week[parse_date["2001-01-01", "Y-m-d"]] = 1

#### Definition#

@inlinedef date_week = rel_primitive_date_week

## datetime_week#

datetime_week[dt, tz]


Week of the year for a DateTime dt, as an integer between 0 and 53 (see date_week).

Note that DateTime properties require a timezone tz.

#### Definition#

@inlinedef datetime_week = rel_primitive_datetime_week

## date_day#

date_day[d]


Day of the month for a Date, as an integer between 1 and 31, inclusive.

Example:

def d = parse_date["2014-10-31", "Y-m-d"]date_day[d] = 31

#### Definition#

@inlinedef date_day = rel_primitive_date_day

## date_dayofweek#

date_dayofweek[d]


Day of the week for a date, as an integer between 1 and 7, where 1 is Monday and 7 is Sunday. (That is, 5 for Friday.)

Example:

def d = parse_date["2014-01-31", "Y-m-d"]date_dayofweek[d] = 5

#### Definition#

@inlinedef date_dayofweek = rel_primitive_date_dayofweek

## date_dayname#

date_dayname[d]


Name of week-day (returns a String, e.g., Friday)

Example:

def t = parse_date["2014-01-31", "Y-m-d"]def output = date_dayname[t]"Friday"

#### Definition#

@inlinedef date_dayname = rel_primitive_date_dayname

## date_dayofweekofmonth#

date_dayofweekofmonth[d]


Day of week of month, as an integer (e.g. 2 for second Friday of the month, 1 for the first Tuesday).

Example:

def t = parse_date["2014-01-31", "Y-m-d"]date_dayofweekofmonth[t] = 5 // fifth Friday of that month

#### Definition#

@inlinedef date_dayofweekofmonth = rel_primitive_date_dayofweekofmonth

## date_monthname#

date_monthname[d]


The month name for date d, as a string.

Example:

def t = parse_date["2014-01-31", "Y-m-d"]date_monthname[t] = "January"

#### Definition#

@inlinedef date_monthname = rel_primitive_date_monthname

## date_daysinmonth#

date_daysinmonth[d]


The number of days in the month for date d

Examples:

def d1 = parse_date["2014-01-30", "Y-m-d"]date_daysinmonth[t] = 31def d2 = parse_date["2014-02-11", "Y-m-d"]date_daysinmonth[d2] = 28def d = parse_date["2016-02-11", "Y-m-d"]date_daysinmonth[d] = 29

#### Definition#

@inlinedef date_daysinmonth = rel_primitive_date_daysinmonth

## date_isleapyear#

date_isleapyear[d]


True iff the year for date d is a leap year.

Examples:

def notleap = parse_date["2014-01-31", "Y-m-d"]def leap = parse_date["2016-01-31", "Y-m-d"]def output = date_isleapyear[notleap]falsedef output = date_isleapyear[leap]true

#### Definition#

@inlinedef date_isleapyear = rel_primitive_date_isleapyear

## date_dayofyear#

date_dayofyear[d]


Day of year

Example:

def t = parse_date["2014-01-31", "Y-m-d"]def output = date_dayofyear[t]31

#### Definition#

@inlinedef date_dayofyear = rel_primitive_date_dayofyear

## date_quarterofyear#

date_quarterofyear[d]


Quarter to year

Example:

def d = parse_date["2014-01-31", "Y-m-d"]date_quarterofyear[d] = 1

#### Definition#

@inlinedef date_quarterofyear = rel_primitive_date_quarterofyear

## date_dayofquarter#

date_dayofquarter[d]


Day of quarter

Example:

def d = parse_date["2014-01-31", "Y-m-d"]date_dayofquarter[d] = 31

#### Definition#

@inlinedef date_dayofquarter = rel_primitive_date_dayofquarter

## datetime_day#

datetime_day[dt, tz]


Day of the month, for a DateTime. Note that DateTime properties require a timezone string tz.

Example:

datetime_day[unix_epoch, "UTC"] = 1datetime_day[unix_epoch, "UTC-10"] = 31

#### Definition#

@inlinedef datetime_day = rel_primitive_datetime_day

## datetime_hour#

datetime_hour[dt, tz]


Hour of a DateTime. Note that DateTime properties require a timezone string tz.

#### Definition#

@inlinedef datetime_hour = rel_primitive_datetime_hour

## datetime_minute#

datetime_minute[dt, tz]


Minute of a DateTime. Note that DateTime properties require a timezone string tz.

#### Definition#

@inlinedef datetime_minute = rel_primitive_datetime_minute

## datetime_second#

datetime_second[dt]


Second of a DateTime. Unlike other DateTime functions, datetime_second does not require a timezone argument.

Example:

datetime_second[unix_epoch] = 0

#### Definition#

@inlinedef datetime_second = rel_primitive_datetime_second

## datetime_year_UTC#

datetime_year_UTC[dt]


Year assuming datetime is in UTC.

#### Definition#

@inlinedef datetime_year_UTC[d] = rel_primitive_datetime_year[d, "UTC"]

## datetime_month_UTC#

datetime_month_UTC[dt]


Month assuming datetime is in UTC.

#### Definition#

@inlinedef datetime_month_UTC[d] = rel_primitive_datetime_month[d, "UTC"]

## datetime_week_UTC#

datetime_week_UTC[dt]


Week assuming datetime is in UTC.

#### Definition#

@inlinedef datetime_week_UTC[d] = rel_primitive_datetime_week[d, "UTC"]

## datetime_day_UTC#

datetime_day_UTC[dt]


Day assuming datetime is in UTC.

#### Definition#

@inlinedef datetime_day_UTC[d] = rel_primitive_datetime_day[d, "UTC"]

## datetime_hour_UTC#

datetime_hour_UTC[dt]


Hour assuming datetime is in UTC.

#### Definition#

@inlinedef datetime_hour_UTC[d] = rel_primitive_datetime_hour[d, "UTC"]

## datetime_minute_UTC#

datetime_minute_UTC[dt]


Minute assuming datetime is in UTC.

#### Definition#

@inlinedef datetime_minute_UTC[d] = rel_primitive_datetime_minute[d, "UTC"]

## datetime_dayofweek#

datetime_dayofweek[dt, tz]


Day of week (returns a number, e.g., 5 for Friday)

Example:

def dt = parse_datetime["2014-01-31 01:00 +03:00", "YYYY-mm-dd HH:MM zzzz"]datetime_dayofweek[dt, "+03:00"] = 5datetime_dayofweek[dt, "UTC"] = 4

#### Definition#

@inlinedef datetime_dayofweek = rel_primitive_datetime_dayofweek

## datetime_dayname#

datetime_dayname[t, tz]


Name of week-day (returns a String, e.g., Friday)

Example:

def t = parse_datetime["2014-01-31 01:00 +03:00", "YYYY-mm-dd HH:MM zzzz"]datetime_dayname[t, "+03:00"] = "Friday"

#### Definition#

@inlinedef datetime_dayname = rel_primitive_datetime_dayname

## datetime_dayofweekofmonth#

datetime_dayofweekofmonth[dt, tz]


Day of week of month, as an integer (e.g. 2 for second Friday of the month, 1 for the first Tuesday).

Example:

def t = parse_datetime["2014-01-31 01:00 +03:00", "YYYY-mm-dd HH:MM zzzz"]datetime_dayofweekofmonth[t, "+03:00"] = 5

#### Definition#

@inlinedef datetime_dayofweekofmonth = rel_primitive_datetime_dayofweekofmonth

## datetime_monthname#

datetime_monthname[dt, tz]


The month name

Example:

def t = parse_datetime["2014-01-31 01:00 +03:00", "YYYY-mm-dd HH:MM zzzz"]datetime_monthname[t, "+03:00"] = "January"

#### Definition#

@inlinedef datetime_monthname = rel_primitive_datetime_monthname

## datetime_daysinmonth#

datetime_daysinmonth[dt, tz]


The number of days in a datetime’s month, adjusting for timezone tz.

Examples:

def t = parse_datetime["2014-02-28 23:00 +00:00", "YYYY-mm-dd HH:MM zzzz"]datetime_daysinmonth[t, "+03:00"] = 31datetime_daysinmonth[t, "-03:00"] = 28

#### Definition#

@inlinedef datetime_daysinmonth = rel_primitive_datetime_daysinmonth

## datetime_isleapyear#

datetime_isleapyear[dt, tz]


Is it a leap year?

Examples:

def dt = parse_datetime["2014-01-31 01:00 +03:00", "YYYY-mm-dd HH:MM zzzz"]def output = datetime_isleapyear[dt, "+03:00"]falsedef dtleap = parse_datetime["2016-01-31 01:00 +03:00", "YYYY-mm-dd HH:MM zzzz"]def output = datetime_isleapyear[dtleap, "+00:00"]true

#### Definition#

@inlinedef datetime_isleapyear = rel_primitive_datetime_isleapyear

## datetime_dayofyear#

datetime_dayofyear[dt, tz]


Day of year

Examples:

def dt = parse_datetime["2014-03-31 01:00 +03:00", "YYYY-mm-dd HH:MM zzzz"]datetime_dayofyear[dt, "+03:00"] = 90datetime_dayofyear[dt, "+00:00"] = 89

#### Definition#

@inlinedef datetime_dayofyear = rel_primitive_datetime_dayofyear

## datetime_quarterofyear#

datetime_quarterofyear[dt, tz]


Quarter of the year for datetime dt, as a number between 1 and 4.

Example:

def t = parse_datetime["2014-01-31 01:00 +03:00", "YYYY-mm-dd HH:MM zzzz"]datetime_quarterofyear[t, "+03:00"] = 1

#### Definition#

@inlinedef datetime_quarterofyear = rel_primitive_datetime_quarterofyear

## datetime_dayofquarter#

datetime_dayofquarter[dt, tz]


Day of quarter

Example:

def t = parse_datetime["2014-01-31 01:00 +03:00", "YYYY-mm-dd HH:MM zzzz"]datetime_dayofquarter[t, "+03:00"] = 31

#### Definition#

@inlinedef datetime_dayofquarter = rel_primitive_datetime_dayofquarter

date_add[d, period]
d + period


Add a Period to a Date

Example:

def d = parse_date["2021-09-21", "Y-m-d"]def output = date_add[d, Day[20]]Dates.Date("2021-10-11")

#### Definition#

@inlinedef date_add = rel_primitive_add_date_period

datetime_add[dt, period]
dt + period


Add a Period to a DateTime

Examples:

def dt = parse_datetime["2021-01-01 01:00:00", "Y-m-d H:M:S"]def output = datetime_add[dt, Year[1]]Dates.DateTime("2022-01-01T01:00:00")def output = datetime_add[dt, Month[13]]Dates.DateTime("2022-02-01T01:00:00")def output = datetime_add[dt, Hour[1000]]Dates.DateTime("2021-02-11T17:00:00")

#### Definition#

@inlinedef datetime_add = rel_primitive_add_datetime_period

## date_subtract#

date_subtract[d, period]
d - period


Subtract a Period from a Date, returning another Date.

Example:

def d = parse_date["2021-09-21", "Y-m-d"]def output = date_subtract[d, Day[1000]]Dates.Date("2018-12-26")

#### Definition#

@inlinedef date_subtract = rel_primitive_subtract_date_period

## datetime_subtract#

datetime_subtract[dt, period]
dt - period


Subtract a Period from a DateTime, returning another DateTime.

Example:

def dt = parse_datetime["2021-01-01 01:00:00", "Y-m-d H:M:S"]def output = datetime_subtract[dt, Hour[1000]]Dates.DateTime("2020-11-20T09:00:00")

#### Definition#

@inlinedef datetime_subtract = rel_primitive_subtract_datetime_period

period_add[period1, period2]


Add two periods. For now, they need to be of the same type.

def output = period_add[Minute[3], Minute[4]]Minute[7]

#### Definition#

@inlinedef period_add = rel_primitive_add

## period_min#

period_min[period1, period2]


Minimum of two periods. The result is expressed as a nanosecond period.

Example:

def output = period_min[Minute[3],Minute[4]] = Minute[3]true

#### Definition#

@inlinedef period_min[x,y] = rel_primitive_min_period[x,y]

## period_max#

period_max[period1, period2]


Maximum of two periods. The result is expressed as a nanosecond period.

Example:

def output = period_max[Minute[3],Minute[4]] = Minute[4]true

#### Definition#

@inlinedef period_max[x,y] = rel_primitive_max_period[x,y]

## unix_epoch#

unix_epoch


The beginning of the UNIX Epoch, midnight on 1 January 1970 (UTC).

#### Definition#

@inlinedef unix_epoch = parse_datetime["1970-01-01 00 UTC", "Y-m-d H Z"]

## datetimes_period_milliseconds#

datetimes_period_milliseconds[dt1, dt2]


Computes the difference between two datetimes, dt1 - dt2, returning the result in milliseconds.

#### Definition#

@inlinedef datetimes_period_milliseconds = rel_primitive_datetimes_period_milliseconds

## datetime_to_nanoseconds#

datetime_to_nanoseconds[dt]


Convert datetime to nanoseconds since the epoch. Assumes dt is in UTC.

#### Definition#

@inlinedef datetime_to_nanoseconds(datetime, v) =    rel_primitive_datetimes_period_nanoseconds(unix_epoch, datetime, p) and    rel_primitive_period_nanoseconds(p, v)    from p

## nanoseconds_to_datetime#

nanoseconds_to_datetime[dt]


Convert nanoseconds to datetime. Equivalent to datetime.datetime.utcfromtimestamp(seconds) in python.

#### Definition#

@inlinedef nanoseconds_to_datetime[nanoseconds] = datetime_add[unix_epoch, Nanosecond[nanoseconds]]

## Year#

Year[n]


Return a Year period value for the given integer n.

Example:

datetime_add[unix_epoch, Year[10]]

#### Definition#

@inlinedef Year = rel_primitive_year

## Month#

Month[n]


Return a Month period value for the given integer n.

Example:

datetime_add[unix_epoch, Month[10]]

#### Definition#

@inlinedef Month = rel_primitive_month

## Week#

Week[n]


Return a Week period value for the given integer n.

Example:

datetime_add[unix_epoch, Week[10]]

#### Definition#

@inlinedef Week = rel_primitive_week

## Day#

Day[n]


Return a Day period value for the given integer n.

Example:

datetime_add[unix_epoch, Day[10]]

#### Definition#

@inlinedef Day = rel_primitive_day

## Hour#

Hour[n]


Return an Hour period value for the given integer n.

Example:

datetime_add[unix_epoch, Hour[10]]

#### Definition#

@inlinedef Hour = rel_primitive_hour

## Minute#

Minute[n]


Return a Minute period value for the given integer n.

Example:

datetime_add[unix_epoch, Minute[100]]

#### Definition#

@inlinedef Minute = rel_primitive_minute

## Second#

Second[n]


Return a Second period value for the given integer n.

Example:

datetime_add[unix_epoch, Second[100]]

#### Definition#

@inlinedef Second = rel_primitive_second

## Millisecond#

Millisecond[n]


Return a Millisecond period value for the given integer n.

Example:

datetime_add[unix_epoch, Millisecond[100000]]

#### Definition#

@inlinedef Millisecond = rel_primitive_millisecond

## Microsecond#

Microsecond[n]


Return a Microsecond period value for the given integer n.

Example:

datetime_add[unix_epoch, Microsecond[10000000]]

#### Definition#

@inlinedef Microsecond = rel_primitive_microsecond

## Nanosecond#

Nanosecond[n]


Return a Nanosecond period value for the given integer n.

Example:

datetime_add[unix_epoch, Nanosecond[10000000000]]Dates.DateTime("1970-01-01T00:00:10")

#### Definition#

@inlinedef Nanosecond = rel_primitive_nanosecond

## is_Year#

is_Year(x)


Holds if x is a Year period.

#### Definition#

@inlinedef is_Year = rel_primitive_Year

## is_Month#

is_Month(x)


Holds if x is a Month period.

#### Definition#

@inlinedef is_Month = rel_primitive_Month

## is_Week#

is_Week(x)


Holds if x is a Week period.

#### Definition#

@inlinedef is_Week = rel_primitive_Week

## is_Day#

is_Day(x)


Holds if x is a Day period.

#### Definition#

@inlinedef is_Day = rel_primitive_Day

## is_Hour#

is_Hour(x)


Holds if x is a Hour period.

#### Definition#

@inlinedef is_Hour = rel_primitive_Hour

## is_Minute#

is_Minute(x)


Holds if x is a Minute period.

#### Definition#

@inlinedef is_Minute = rel_primitive_Minute

## is_Second#

is_Second(x)


Holds if x is a Second period.

#### Definition#

@inlinedef is_Second = rel_primitive_Second

## is_Millisecond#

is_Millisecond(x)


Holds if x is a Millisecond period.

#### Definition#

@inlinedef is_Millisecond = rel_primitive_Millisecond

## is_Microsecond#

is_Microsecond(x)


Holds if x is a Microsecond period.

#### Definition#

@inlinedef is_Microsecond = rel_primitive_Microsecond

## is_Nanosecond#

is_Nanosecond(x)


Holds if x is a Nanosecond period.

#### Definition#

@inlinedef is_Nanosecond = rel_primitive_Nanosecond

## Date#

Date(x)


Holds if x is a Date.

#### Definition#

@inlinedef Date = rel_primitive_Date

## DateTime#

DateTime(x)


Holds if x is a DateTime.

#### Definition#

@inlinedef DateTime = rel_primitive_DateTime

## datetime_now#

datetime_now


Returns current UTC time (start time of transaction) as a DateTime value.

Example:

def output = datetime_now

#### Definition#

@inlinedef datetime_now = rel_primitive_transaction_edb[:txn_start_time]

## boolean_true#

boolean_true(x)


Holds if x is a Boolean of value true.

#### Definition#

@inlinedef boolean_true = rel_primitive_boolean_true

## boolean_false#

boolean_false(x)


Holds if x is a Boolean of value false.

#### Definition#

@inlinedef boolean_false = rel_primitive_boolean_false

## Boolean#

Boolean(x)


Holds if x is a Boolean.

Example:

def json = parse_json[\"\"\"{"a": true, "b": false}\"\"\"]def output(x) = json(:a, x) and Boolean(x)

#### Definition#

@inlinedef Boolean = rel_primitive_Boolean

## boolean_and#

boolean_and(x, y, z)


Logical AND operator for the Boolean data type.

Example:

def output(x, y, z) = boolean_and(x, y, z) and boolean_true(z)

#### Definition#

@inlinedef boolean_and(x in Boolean, y in Boolean, z in Boolean) =    if boolean_true(x) and boolean_true(y) then        boolean_true(z)    else        boolean_false(z)

## boolean_or#

boolean_or(x, y, z)


Logical or operator for the Boolean data type. Example:

def output(x, y, z) = boolean_or(x, y, z) and boolean_false(z)

#### Definition#

@inlinedef boolean_or(x in Boolean, y in Boolean, z in Boolean) =    if boolean_false(x) and boolean_false(y) then        boolean_false(z)    else        boolean_true(z)

## boolean_not#

boolean_not(x,y)


Negation(not) operator for the Boolean data type. Example:

def output(x, y) = boolean_not(x, y) and boolean_false(x)

#### Definition#

@inlinedef boolean_not(x in Boolean, y in Boolean) =    if boolean_true(x) then        boolean_false(y)    else        boolean_true(y)

## ∧#

F and G
F ∧ G


Logical and (conjunction).

#### Definition#

@inlinedef (∧)(F, G) = F and G

## ∨#

F or G
F ∨ G


Logical or (disjunction), for boolean (arity 0, true or false) arguments F and G.

#### Definition#

@inlinedef (∨)(F, G) = F or G

## ⇒#

F implies G
F ⇒ G
G ⇐ F


Logical implication, for boolean (arity 0, true or false) arguments F and G.

#### Definition#

@inlinedef (⇒)(F, G) = F implies G@inlinedef (⇐)(F, G) = G implies F

## ¬#

not F
¬F


Logical negation, for boolean (arity 0, true or false) argument F.

#### Definition#

@inlinedef (¬)(F) = not F

## iff#

F iff G
F ≡ G
F ⇔ G


If and only if (boolean equivalence), for boolean (arity 0, true or false) arguments F and G.

#### Definition#

@inlinedef iff(F, G) = (F implies G) and (G implies F)@inlinedef (≡)(F, G) = F iff G@inlinedef (⇔)(F, G) = F iff G

## xor#

F xor G
F ≢ G
F ⇎ G
F ⊻ G


Exclusive OR, for boolean (arity 0, true or false) arguments F and G.

#### Definition#

@inlinedef xor(F, G) = not(F ≡ G)@inlinedef (⊻)(F, G) = F xor G@inlinedef (≢)(F, G) = F xor G@inlinedef (⇎)(F, G) = F xor G

## intersect#

intersect[R, S]
R ∩ S


Intersect two n-ary relations R and S

#### Definition#

@inlinedef intersect[R, S](x...) = R(x...) and S(x...)@inlinedef (∩) = intersect

## union#

union[R, S]
R ∪ S


Union two n-ary relations R and S

#### Definition#

@inlinedef union[R, S](x...) = R(x...) or S(x...)@inlinedef (∪) = union

## cart#

cart[R, S]
R × S


Cartesian product.

Examples:

def output = 1 ✕ 2(1,2)def output = {1; 2} ✕ {3; 4}(1,3)(1,4)(2,3)(2,4)

#### Definition#

@inlinedef cart[R, S](x..., y...) = R(x...) and S(y...)@inlinedef (×) = cart

## diff#

diff[R, S]


Set difference (complement): removes the tuples of S from R, if present.

Example:

def output = diff[{1;2;3;4} , {1;3} ]24

#### Definition#

@inlinedef diff[R, S](x...) = R(x...) and not S(x...)

## complement#

complement[R]


The complement of relation R

#### Definition#

@inlinedef complement[R](x...) = not R(x...)

## domain#

domain[F]


The domain of a scalar function F. The domain represents all but the last argument of F.

Example:

def output = domain[{(1, 'a', 1}; (2, 'b', 4); (3, 'c', 9)}](1, 'a')(2, 'b')(3, 'c')

#### Definition#

@inlinedef domain[F](k...) = F(k..., _)

## first#

first[R]


Projection to the first argument of R.

first supports heterogeneous relations, both in arity and types.

Examples:

def output = first[(1, 2, 3); (4, 5, 6)]14def output = first[(1, 2, 3); (4, 5); 6]146def output = first[("a", 1); (2, 3)]2"a"

#### Definition#

@inlinedef first[R](x)  = ∃(y... : R(x, y...))

## second#

second[R]


Projection to the second argument of R.

second supports heterogeneous relations, both in arity and types.

Examples:

def output = second[(1, 2, 3); (4, 5)]25def output = second[(1, 2); (3, "abc")]2"abc"

#### Definition#

@inlinedef second[R](x) = ∃(y... : R(_, x, y...))

## last#

last[R]


Projection to the last argument of the relation R.

last supports heterogeneous relations, both in arity and types.

Examples:

def output = last[(1, 2, 3); (4, 5, 6)]36def output = last[1; 2; 3]123def output = last[(1, 2); (3, "abc")]2"abc"def output = last[(1, 2, 3); (4, 5)]35

#### Definition#

@inlinedef last[R](y)   = ∃(x... : R(x..., y))

## transpose#

transpose[R]


Transpose a binary relation (swap the two arguments).

Example:

def output = transpose[{(1, 2); (3, 4)}](2, 1)(4, 3)

#### Definition#

@inlinedef transpose[R](y, x) = R(x, y)

## empty#

empty(R)


Examples:

• empty(1) is false
• empty(true) is false
• empty(false) is true

#### Definition#

@inlinedef empty(R) = not exists(x...: R(x...))

## subset#

subset(R, S)
R ⊆ S


R is a subset of S if all facts of R is also in S.

Subset is the relational variant of implication, but note that there is a subtle difference for arity-overloaded relations due to usage of varargs.

• forall(x, y: R(x, y) implies S(x, y)) is true if the implication is true for all binary facts of R. If R also has facts of a different arity, then the implication remains true, even when R ⊄ S.

• subset(R, S), defined as forall(xs... where R(xs...) : S(xs...)) is true only if there exists no fact in R, of any arity, that is not in S.

#### Definition#

@inlinedef subset(R, S) = forall(x... where R(x...): S(x...))@inlinedef (⊆) = subset

## proper_subset#

proper_subset(R, S)
R ⊂ S


R is a proper subset of S if subset(R, S) and R and S are not equal. This means there has to be at least one fact in S that is not in R.

#### Definition#

@inlinedef proper_subset(R, S) = subset(R, S) and not equal(R, S)@inlinedef (⊂) = proper_subset

## superset#

superset(R, S)
R ⊇ S


Inverse of subset. See subset.

#### Definition#

@inlinedef superset(R, S) = forall(x... where S(x...): R(x...))@inlinedef (⊇) = superset

## proper_superset#

proper_superset(R, S)
R ⊃ S


Inverse of proper_subset. See proper_subset.

#### Definition#

@inlinedef proper_superset(R, S) = superset(R, S) and not equal(R, S)@inlinedef (⊃) = proper_superset

## disjoint#

disjoint(R, S)


R and S are disjoint if they have no fact in common.

#### Definition#

@inlinedef disjoint(R, S) = empty(R ∩ S)

## dot_join#

dot_join[R, S]
R . S


Compose

#### Definition#

@inlinedef dot_join[R,S](x..., y...) = exists(t: R(x..., t) and S(t, y...))@inlinedef (.) = dot_join

## prefix_join#

prefix_join[R, S]
R <: S


The prefix join (or restriction) of S to R is the subset of tuples of S where there is a prefix of the tuple in R.

ExampleNormalized
n <: edgex, y: edge(x, y) and x = n
female <: parentx, y: female(x) and parent(x, y)
t <: playersx, p: players(x, p) and t = x
t.players <: agep, v: players(t, p) and age(p, v)
intern <: salaryp, v: intern(p) and salary(p, v)

The restriction operator can also be used to select subsets of JSON-like relations:

• :a <: json where json is {"a": {"b": 1, "c": 2}, "d": 3} has value {"a": {"b": 1, "c": 2}}

• (:[], _, :a) <: json where json is [ {"a": 1, "b": 2}, {"a": 3, "b": 4} ] has value [ {"a": 1}, {"a": 3} ].

#### Definition#

@inlinedef prefix_join[R, S](x..., y...) = R(x...) and S(x..., y...)@inlinedef (<:) = prefix_join

## suffix_join#

suffix_join[R, S]
R :> S


The suffix join (or restriction) of R to S is the subset of tuples of R where there is a suffix of the tuple in S.

ExampleNormalized
edge :> nx, y: edge(x, y) and y = n
parent :> femalex, y: parent(x, y) and female(y)
account_balance :> positivex, v: account_balance(x, v) and positive(v)
brand_name :> "Tesla"b, s: brand_name(b, s) and s = "Tesla"

The restriction operator can also be used to select subsets of JSON-like relations:

• json :> even where json is [ {"a": 1, "b": 2}, {"a": 3, "b": 4, "c": 6} ] has value [ {"b": 2}, {"b": 4, "c": 6} ]

• json :> (:b, even) where json is [ {"a": 1, "b": 2}, {"a": 3, "b": 4, "c": 6} ] has value [ {"b": 2}, {"b": 4} ]

#### Definition#

@inlinedef suffix_join[R, S](x..., y...) = R(x..., y...) and S(y...)@inlinedef (:>) = suffix_join

## left_override#

left_override[R, S]
R <++ S


The (left) override operator is intended to be applied to relations with functional dependencies from all but the last argument (the key) to the last argument (the value).

The (left) override of R and S consist of all the tuples of R and all the tuples in S for which the key is not in R. Often, S is used for default values.

ExampleValue
2 <++ 32
1.5 <++ 31.5
(1,2) <++ (1,3)(1,2)
(3,4) <++ (1,2); (3,5)(1,2); (3,4)
(3,"abc") <++ (1,2); (3,5)(1,2); (3,"abc")
(1,2); (3,5) <++ (3,4); (6,7)(1,2); (3,5); (6,7)

Override can be applied to heterogeneous relations, notably JSON-like relations. The following examples show <++ operators applied to JSON inputs.

LeftRightValue
{"a": 1, "b": 3}{"a": 2 }{"a": 1, "b": 3}
{"a": 2 }{"a": 1, "b": 3}{"a": 2, "b": 3}
{"a": 1, "b": 2}{"c": 3}{"a": 1, "b": 2, "c": 3}

#### Definition#

@inlinedef left_override[R, S](xs..., v) = R(xs..., v)@inlinedef left_override[R, S](xs..., v) = S(xs..., v) and not R(xs..., _)@inlinedef (<++) = left_override

## right_override#

right_override[R, S]
R ++> S


Right override is identical to left override, except the arguments are swapped.

A few examples to illustrate the difference with left-override:

ExampleValue
2 ++> 33
(1,2) ++> (1,3)(1,3)
(3,4) ++> (1,2); (3,5)(1,2); (3,5)
(3,"abc") ++> (1,2); (3,5)(1,2); (3,5)
(1,2); (3,5) ++> (3,4); (6,7)(1,2); (3,4); (6,7)

#### Definition#

@inlinedef right_override[R, S](xs..., v) = S(xs..., v)@inlinedef right_override[R, S](xs..., v) = R(xs..., v) and not S(xs..., _)@inlinedef (++>) = right_override

## function#

function(R)


Given a relation R, true if R is a function, and false if not.

Examples:

def output = function[{(1, 2); (2, 5)}]truedef output = function[{(1, 2); (1, 3)}]false

#### Definition#

@inlinedef function(R) =    forall(k..., v1, v2 where R(k..., v1) and R(k..., v2): v1 = v2)

## total#

total(D, F)


Given a domain D and a relation F, check that there is a value in F for every element of the domain D. The arity of F must be the arity of D + 1.

#### Definition#

@inlinedef total(D, F) =    forall(k... where D(k...): F(k..., _))

## default_value#

default_value[D, F, c]


Make function or relation F total for domain D by defaulting to c.

The arity of F must be the arity of D + 1.

Example:

def dom = {1;2;3;4}def f = {(1, 321); (3, 123)}def output = default_value[dom, f, 42](1, 321)(2, 42)(3, 123)(4, 42)

#### Definition#

@inlinedef default_value[D, F, c](k..., v) =    F(k..., v) or (D(k...) and not F(k..., _) and v = c)

## missing#

missing


Singleton missing value.

Examples:

missing[] = missingequal( (x : missing(x)) , {missing} )

#### Definition#

@inlinedef missing = rel_primitive_missing

## relname_string#

relname_string[relname]


Returns the string corresponding to the given relation name. Example: relname_string[:foobar] gives “foobar” .

#### Definition#

@inlinedef relname_string = rel_primitive_relname_string

## arity#

arity[R]


The arity of a relation.

Arity is a higher-order relation that is always evaluated at compile-time.

Examples:

def output = arity[3]1def output = arity[{1; 2; 3}]1def output = arity[(1, 2)]2def output = arity[add]3def output = arity[{1; 2; (1,2)}]12

Arity can be used to do meta-programming in logic. For example, the following abstraction verbalize implements specific cases using arity.

Examples:

@inline def verbalize[R] = "nullary", arity[R] = 0;                            "unary", arity[R] = 1;                            "binary", arity[R] = 2def output = verbalize[true]"nullary"def output = verbalize[1]"unary"

Arity can be used in higher-order abstractions to check at compile-time that they are used correctly.

Arity can be used in integrity constraints to state expectation on EDB or IDB relations. Because arity is evaluated at compile-time, it can catch mistakes in the logic before the logic executes.

Example:

def p = 1,2,3ic { arity[p] = 3 }

Note that there is a difference between R(_, _) and arity(R) = 2. The first requires R to be non-empty, which is an runtime property of R.

#### Definition#

@inlinedef arity[R] = rel_primitive_arity[R]

## pivot#

pivot[R]


Associates each element of an input tuple with its index in the tuple. The result is always a binary relation.

pivot[(t1, ..., tn)] generates pairs (1, t1);... (i, ti); ... (n, tn) This is useful to match up long tuples with names (see zip), for example.

Example:

def output = pivot[{(5, 60, 7, 2)}](1, 5)(2, 60)(3, 7)(4, 2)

pivot[true] and pivot[false] are both false (the empty relation) For unary relations, pivot[{(x)}] is {(1,x)}

#### Definition#

@inlinedef pivot[R] = rel_primitive_pivot[R]

## zip#

zip[R, S]


Pair-wise combine two n-ary tuples into a relation of n pairs.

Example:

def foods = {(:hamburger, :chicken, :hot_dog, :fries, :macaroni, :pizza, :salad, :milk, :ice_cream)}def cost = { (2.49, 2.89, 1.50, 1.89, 2.09, 1.99, 2.49, 0.89, 1.59) }def output = zip[foods, cost](:chicken, 2.89)(:fries, 1.89)(:hamburger, 2.49)(:hot_dog, 1.5)(:ice_cream, 1.59)(:macaroni, 2.09)(:milk, 0.89)(:pizza, 1.99)(:salad, 2.49)

#### Definition#

@inline def zip[R,S](x, y) = rel_primitive_pivot[R](i, x) and rel_primitive_pivot[S](i, y) from i

## jacobian#

jacobian[S, R]


Compute the Jacobian (e.g. the derivative or gradient) of relation S w.r.t. relation R.

Consider the following Rel program, whose inputs are two relations A and x corresponding to a matrix and a vector respectively. It defines a scalar J := x' * A * x. It also defines ∇ and H to be the gradient and Hessian of J w.r.t. x.

Examples:

// J = x' *A *xdef J = sum[i j : x[i] * A[i, j] * x[j]]def ∇ = rel_primitive_jacobian[J, x]def H = rel_primitive_jacobian[∇, x]

The AD transformation converts the above program into the following:

Examples:

// J = x' * A * xdef J = sum[i j : x[i] * A[i, j] * x[j]]// ∇1 = A * xdef ∇1[i] = sum[j v : x[i] = _ and v = A[i, j] * x[j]]// ∇2 = A' * xdef ∇2[j] = sum[i v : v = x[i] * A[i, j] and x[j] = _]// ∇ = ∇1 + ∇2def ∇(i, v) = (v = ∇1[i] + ∇2[i])    or (not(∇1[i] = _) and v = ∇2[i])    or (not(∇2[i] = _) and v = ∇1[i])// H1 = Adef H1[i, j] = sum[v : x[i] = _ and v = A[i, j] and x[j] = _]// H2 = A'def H2[j, i] = sum[v : x[i] = _ and v = A[i, j] and x[j] = _]// H = H1 + H2def H(i, j, v) = (v = H1[i, j] + H2[i, j])    or (not(H1[i, j] = _) and v = H2[i, j])    or (not(H2[i, j] = _) and v = H1[i, j])

#### Definition#

@inlinedef jacobian[S, R] = rel_primitive_jacobian[S, R]

## int#

int[n, v]


Return an n-bit signed integer value from the integer value v.

#### Definition#

@inlinedef int = rel_primitive_int

## uint#

uint[n, v]


Return an n-bit unsigned integer value from the integer value v.

#### Definition#

@inlinedef uint = rel_primitive_uint

## decimal#

decimal[n, digits, v]


Return an n-bit decimal value with digits precision from number value v.

#### Definition#

@inlinedef decimal = rel_primitive_decimal

## rational#

rational[n, num, denom]


Return an n-bit rational value from integer numerator num and denominator denom.

#### Definition#

@inlinedef rational = rel_primitive_rational

## float#

float[n, v]


Return an n-bit floating point value from the number v. Example: float[64, 3.0].

#### Definition#

@inlinedef float = rel_primitive_float

## int64#

int64[v]


Return a 64-bit signed integer value from the integer value v.

#### Definition#

@inlinedef int64 = int[64]

## int128#

int128[v]


Return a 128-bit signed integer value from the integer value v.

#### Definition#

@inlinedef int128 = int[128]

## uint64#

uint64[v]


Return a 64-bit unsigned integer value from the integer value v.

#### Definition#

@inlinedef uint64 = uint[64]

## uint128#

uint128[v]


Return a 128-bit unsigned integer value from the integer value v.

#### Definition#

@inlinedef uint128 = uint[128]

## float64#

float64[v]


Return a 64-bit floating point value from the number v, which must be a float.

#### Definition#

@inlinedef float64 = float[64]

## numerator#

numerator[x]


Numerator of a rational-like number.

Examples:

numerator[rational[64, 1, 3]] = 1numerator[rational[64, 1, 100]] = 1numerator[rational[64, 1, 100] + rational[64, 1, 3]]  =  103numerator[parse_decimal[64, 2, "3.14"]]  =  314numerator[parse_decimal[64, 5, "3.14159"]]  =  314159numerator[5]  =  5

#### Definition#

@inlinedef numerator = rel_primitive_numerator

## denominator#

denominator[x]


Denominator of a rational-like number.

Examples:

denominator[rational[64, 1, 3]] = 3denominator[rational[64, 1, 100]] = 100denominator[rational[64, 1, 100] + rational[64, 1, 3]] = 300denominator[parse_decimal[64, 2, "3.14"]] = 100denominator[parse_decimal[64, 5, "3.14159"]] = 10000denominator[5] = 1

#### Definition#

@inlinedef denominator = rel_primitive_denominator

## int_float_convert#

int_float_convert[x]


Conversion from int to float. Argument must be an int.

Example:

int_float_convert[3] = 3.0int_float_convert[3.2] : error

#### Definition#

@inlinedef int_float_convert = rel_primitive_int_float_convert

## float_int_convert#

float_int_convert[x]


Conversion from float to int. Gives an error if the argument is not equivalent to an int. (See trunc_to_int, floor_to_int for general conversion.)

Example:

float_int_convert[3.0] = 3float_int_convert[3.2] : error

#### Definition#

@inlinedef float_int_convert = rel_primitive_float_int_convert

## rational_convert#

rational_convert[n, x]


Convert a number x to a rational with n-bit integer representation.

Any type that supports numerator and denominator is supported.

Examples:

rational_convert[64, 3]  =  (3//1,)rational_convert[64, decimal[64, 2, 0.75]]  =  (3//4,)

#### Definition#

@inlinedef rational_convert[n, a] =    rational[n, numerator[a], denominator[a]]

## Any#

Any(x)


Holds for any x

#### Definition#

@inlinedef Any(x) = true

## Number#

Number(x)


Holds if x is a number (for example, Int ,Float, or their fixed-width versions). See also Int and Float in intrinsics.rel.

#### Definition#

@inlinedef Number = rel_primitive_Number

## Char#

Char(x)


Holds if x is a Char

#### Definition#

@inlinedef Char = rel_primitive_Char

## String#

String(x)


Holds if x is a String

#### Definition#

@inlinedef String = rel_primitive_String

## Missing#

Missing(x)


Holds if x is Missing.

#### Definition#

@inlinedef Missing = rel_primitive_Missing

## Floating#

Floating(n, x)


Holds if x is an n-bit floating point number.

#### Definition#

@inlinedef Floating = rel_primitive_Floating

## UnsignedInt#

UnsignedInt(n, x)


Holds if x is an n-bit unsigned integer. Example: UnsignedInt(8, uint[8, 3]) is true.

#### Definition#

@inlinedef UnsignedInt = rel_primitive_UnsignedInt

## SignedInt#

SignedInt(n, x)


Holds if x is an n-bit signed integer. Example: SignedInt(32, int[32, 3]) is true.

#### Definition#

@inlinedef SignedInt = rel_primitive_SignedInt

## Rational#

Rational(n, x)


Holds if x is an n-bit rational.

#### Definition#

@inlinedef Rational = rel_primitive_Rational

## FixedDecimal#

FixedDecimal(n, digits, x)


Holds if x is an n-bit fixed decimal with digits precision.

#### Definition#

@inlinedef FixedDecimal = rel_primitive_FixedDecimal

## RelName#

RelName(x)


Holds if x is a relation name. Example: RelName(:myrel) is true.

#### Definition#

@inlinedef RelName = rel_primitive_RelName

## Entity#

Entity(x)


Test if the given value is an entity.

#### Definition#

@inlinedef Entity = rel_primitive_Entity

## AutoNumber#

AutoNumber(x)


Test if the given value is an AutoNumberValue.

#### Definition#

@inlinedef AutoNumber = rel_primitive_AutoNumberValue

## Hash#

Hash(x)


Test if the given value is a HashValue.

#### Definition#

@inlinedef Hash = rel_primitive_HashValue

## FilePos#

FilePos(x)


Test if the given value is a FilePos.

#### Definition#

@inlinedef FilePos = rel_primitive_FilePos// Temporary alias for backward compatibility@inlinedef delve_period_days = rel_primitive_period_days// Temporary alias for backward compatibility@inlinedef delve_date_daysinmonth = rel_primitive_date_daysinmonth

int_spread_by_even[R, value]


Spreads value to the entries in the relation R evenly as whole units. If the value to spread = 50 and R has 5 elements, each element will get 10. In case of uneven spread (e.g. spread 51 to 5 elements), the remainder gets distributed as single units in order starting from the first element after the relation has been sorted lexicographically (for details see sort). If value is negative, an empty relation is returned.

Example:

def R = {("Atlanta", "Georgia");    ("Seattle", "Washington");    ("San Francisco", "California")}def output = int_spread_by_even[R, 32]("Atlanta", "Georgia", 11)("San Francisco", "California", 11)("Seattle", "Washington", 10)

#### Definition#

@inlinedef int_spread_by_even[R, val] = v..., s:    Int(val) and    R(v...) and    val >= 0 and    c = count[R] and    sort[R](i, v...) and    (        (i <= remainder[val, c] and s = trunc_divide[val, c] + 1) or        (i > remainder[val, c] and s = trunc_divide[val, c])    )    from i, c

int_spread_by_ratio[R, value]


Spreads value to the entries in the relation R proportionally to their weight (which is the last element in each tuple), as whole units. For example, if the relation is {("X",90); ("Y",10)}, "X" will get 90% of value and "Y" will get 10%. Often, this split will result in a decimal number, but we want to spread whole units. To resolve this issue, we first distribute the floor value of the decimal number computed. The remainder gets distributed as single units in order starting from the element that had the highest decimal value. If value is negative, an empty relation is returned.

Example:

def R = {("Atlanta", "Georgia", 50);
("Seattle", "Washington", 80);
("San Francisco", "California", 10)}

("Atlanta", "Georgia", 11)
("San Francisco", "California", 2)
("Seattle", "Washington", 17)


#### Definition#

@inlinedef int_spread_by_ratio[R, val] = v..., s:    Int(val) and    R(v..., w) and    val >= 0 and    forall(t in last[R] : t > 0) and    s = floor_to_int[val * (w / sum[R])] + offset and    sort[(rr, vv...) : rr = remainder[R[vv...] * val, sum[R]]](i, r, v...) and    c = val - sum[vv... : floor_to_int[val * (R[vv...] / sum[R])]] and    (        (offset = 1 and i >= count[R] - c + 1) or        (offset = 0 and i < count[R] - c + 1)    )    from w, i, r, c, offset

FixedDecimal_spread[mode, R, val]


This definition uses the two spread strategies implemented in int_spread_by_even and int_spread_by_ratio but specialized to input value that is a FixedDecimal. The major difference here is that in the integer case, the smallest unit to spread was 1, whereas here, the smallest unit to spread is 10^(-d) where d is the number of digits used in the FixedDecimal value val. For example, if we are trying to spread the value 3.140, the smallest unit to spread will be 0.001. mode can be :even or :ratio.

Example:

def R = {("Atlanta", "Georgia", 50);    ("Seattle", "Washington", 80);    ("San Francisco", "California", 10)}def output = FixedDecimal_spread[:even, R, decimal[64, 3, 3.14]]("Atlanta", "Georgia", 1.047)("San Francisco", "California", 1.047)("Seattle", "Washington", 1.046)

#### Definition#

@inlinedef FixedDecimal_spread[mode, R, val] = v..., s:    rel_primitive_decimal_type(val, decimal_bit_length[val], decimal_precision[val]) and    den = denominator[val] and    digits = floor_to_int[log10[den]] and    valinput = numerator[val] and    (        (mode = :even and s = int_spread_by_even[R, valinput][v...] / den) or        (mode = :ratio and s = int_spread_by_ratio[R, valinput][v...] / den)    )    from valinput, digits, den

spread[mode, R, val]


This definition unifies the spread definitions on integers and FixedDecimal values using the two spreading strategies. Namely, this definition wraps FixedDecimal_spread, int_spread_by_even, and int_spread_by_ratio.

mode can be :even for even spread, or :ratio for ratio spread. R is the relation to execute the spread on. val is the value to spread.

Example:

def R = {("Atlanta", "Georgia", 50);    ("Seattle", "Washington", 80);    ("San Francisco", "California", 10)}def out1 = spread[:even, R, decimal[64, 3, 31.0]]("Atlanta", "Georgia", 50, 10.334)("San Francisco", "California", 10, 10.333)("Seattle", "Washington", 80, 10.333)def out2 = spread[:even, R, 31]("Atlanta", "Georgia", 50, 11)("San Francisco", "California", 10, 10)("Seattle", "Washington", 80, 10)

#### Definition#

@inlinedef spread[mode, R, val](v...) =(    (Int(val) and mode = :even and int_spread_by_even[R, val](v...)) or    (Int(val) and mode = :ratio and int_spread_by_ratio[R, val](v...)) or    (        rel_primitive_decimal_type(val, decimal_bit_length[val], decimal_precision[val]) and        FixedDecimal_spread[mode, R, val](v...)    ))

## formula_card_est#

formula_card_est[R]


Return the cardinality estimate of a given relational abstraction R as estimated by the physical query optimizer. The returned estimate is represented as a Float. It is typically an upper bound on the actual cardinality and can suffer from a numeric overflow, e.g. if the formula R is a big cross-product of relations. To avoid this, use the log-version log_card_est[R]. See log_card_est for more details.

Examples:

def card = formula_card_est[R]
def card = formula_card_est[a, b, c: R(a, b) and S(b, c) and T(a, c)]


#### Definition#

@inlinedef formula_card_est[R] = 2.0 ^ rel_log_card_est[R]

## log_card_est#

log_card_est[R]


Return the log base 2 of the cardinality estimate of a given relational abstraction R.

#### Definition#

@inlinedef log_card_est[R] = rel_log_card_est[R]