The Standard Library (stdlib)
Broad collection of Rel relations that perform essential and commonly used tasks.
^Date
View source^Date(n, d)
Create a Date, d
, representing the date at day n
of the proleptic Gregorian calendar.
Example:
def output(d) = ^Date(734503, d)
//output> 2012-01-01
For more details, see the rel:base:^Date
docstring.
^Date
View source^Date[year in Int, month in Int, day in Int]
Create a Date from its three components: year, month and day. The three arguments are required to be Int64.
^Date
View source^Date[dt in DateTime, tz in String]
Create a Date
from a DateTime
, with timezone tz
.
The timezone argument is necessary for the Date
because DateTime
is an instant of time
that is timezone independent. For different locations on earth (timezones), a DateTime
has
different dates.
^DateTime
View source^DateTime(n, dt)
Create a DateTime, dt
, representing the date at millisecond n
of the proleptic Gregorian calendar.
Example:
def output(dt) = ^DateTime(63568386000000, dt)
//output> 2015-05-27T05:00:00.000Z
For more details, see the rel:base:^DateTime
docstring.
^DateTime
View source^DateTime[year, month, day, hour, minute, second, millisecond, tz in String]
Create a DateTime
from a year, month, day, hour, minute, second, and millisecond.
The timezone argument tz
is necessary to correctly interpret what instant in time this is.
There can be multiple DateTime
values for one set of arguments: for example, with the
ending of daylight saving time at 2am, every time between 1am and 2am occurs twice and has
two corresponding instants of time.
For part values that are out of range, there are no tuples (there is no error).
^DateTime
View source^DateTime[date, hour, minute, second, millisecond, tz in String]
Create a DateTime
from a date, hour, minute, second, and millisecond.
This constructor uses the year, month, and day from the date
and then
constructs a DateTime
in the same way as the constructor with all parts as arguments.
^DateTime
View source^DateTime[year, month, day, tz in String]
Create a DateTime
for the given year, month, and day, with the time components all set to 0.
The resulting DateTime
is the first millisecond for the given date and time zone tz
.
See the ^DateTime constructor with time components as arguments for more details.
^DateTime
View source^DateTime[date in Date, tz in String]
Create a DateTime
for the given Date
, with the time components all set to 0.
The resulting DateTime
is the first millisecond of the given Date
and time zone tz
.
See the ^DateTime constructor with time components as arguments for more details.
^FilePos
View source^FilePos(y, x)
Brings the value type constructor ^FilePos
from the module rel:base
into the global namespace.
For more details, see the rel:base:^FilePos
docstring.
∨
View sourceF or G
F ∨ G
Logical or (disjunction), for boolean (arity 0, true or false) arguments F and G.
acos
View sourceacos[x]
acos(x, ac)
Arccosine of x
. ac
is the arccosine of x
given in radians.
Parameters
Parameter | Type | Description |
---|---|---|
x | FloatBinary[#64] , SignedInteger[#64] | Cosine of ac . Must be grounded. |
ac | FloatBinary[#64] | Arccosine of x in radians. |
Explanation
Defined for x
between -1 and 1 (inclusive).
The value of ac
ranges from 0 to π.
Arccosine is sometimes called “inverse cosine.”
Only 64-bit float and 64-bit integer values for x
are supported.
Examples
Calculate the arccosine of 0:
def output = acos[0]
//output> 1.5707963267948966
Calculate the arccosine of -1 using full expression:
def output(x) = acos(-1, x)
//output> 3.141592653589793
Confirm that 1.5707963267948966 is the arccosine of 0:
def output = acos(0, 1.5707963267948966)
//output> () // true
See Also
acosh
View sourceacosh[x]
acosh(x, ach)
Hyperbolic arccosine. ach
is the hyperbolic arccosine of x
.
Parameters
Parameter | Type | Description |
---|---|---|
x | FloatBinary[#64] , SignedInteger[#64] | Hyperbolic cosine of ach . Must be grounded. |
ach | FloatBinary[#64] | Hyperbolic arccosine of x . |
Explanation
Defined for x
>= 1.
Hyperbolic arccosine is sometimes called “inverse hyperbolic cosine.”
Only 64-bit float and 64-bit integer values for x
are supported.
Examples
Calculate the hyperbolic arccosine of 90:
def output = acosh[90]
//output> 5.192925985263684
Calculate the hyperbolic arccosine of 180 using full expression:
def output(x) = acosh(180, x)
//output> 5.886096315311465
Confirm that 5.192925985263684 is the hyperbolic arccosine of 90:
def output = acosh(90, 5.192925985263684)
//output> () // true
See Also
acot
View sourceacot[x]
acot(x, act)
Arccotangent. act
is the arccotangent of x
.
Parameters
Parameter | Type | Description |
---|---|---|
x | FloatBinary[#64] , SignedInteger[#64] | Cotangent of act . Must be grounded. |
act | FloatBinary[#64] | Arccotangent of x . |
Explanation
Arccotangent is sometimes called “inverse cotangent.”
Only 64-bit float and 64-bit integer values for x
are supported.
Examples
Calculate the arccotangent of 1:
def output = acot[1]
//output> 0.7853981633974483
Calculate the arccotangent of -1 using full expression:
def output(x) = acot(-1, x)
//output = -0.7853981633974483
Confirm that 0.7853981633974483 is the arccotangent of 1:
def output = acot(1, 0.7853981633974483)
//output> () // true
See Also
add
View sourceadd[x, y]
add(x, y, s)
x + y
Addition of two numbers.
Addition of a DateTime
/Date
, x
, with a time duration y
.
Parameters
Numeric Data
Parameter | Type | Description |
---|---|---|
x | Number | First summand. |
y | Number | Second summand. |
s | Number | Sum x + y . |
Not all numeric values can be mixed with each other. The following combinations work:
x | y | s |
---|---|---|
Number | Same as x | Same as x |
Rational , FixedDecimal | SignedInteger[#64] | Same as x |
SignedInteger[#64] | SignedInteger[#128] , Rational , FixedDecimal , FloatBinary[#64] | Same as y |
SignedInteger[#128] | SignedInteger[#64] | SignedInteger[#128] |
FloatBinary[#64] | SignedInteger[#64] | FloatBinary[#64] |
Two of the three arguments need to be grounded. Valid grounding combinations are as follows:
x
andy
.x
ands
.y
ands
.
Time Data
Parameter | Type | Description |
---|---|---|
x | Date , DateTime , date period, time period | First summand. |
y | Date , DateTime , date period, time period | Second summand. |
s | Date , DateTime , date period, time period | Sum x + y . |
The following combinations work:
x | y | s |
---|---|---|
date period, time period | Same date period, time period as x | Same date period, time period as x |
date period, time period | DateTime | DateTime |
DateTime | date period, time period | DateTime |
date period | Date | Date |
Date | date period | Date |
Two of the three arguments need to be grounded. Valid grounding combinations are as follows:
x
andy
.x
ands
.y
ands
.
Explanation
Addition evaluates the sum of x
and y
and assigns it to s
.
In procedural languages, usually x
and y
are given.
In Rel — a declarative language — addition can be thought of as a mapping where x
and y
are the keys and s
is the value, which is functionally dependent on x
and y
.
However, with addition — add(x, y, s)
— it is sufficient to know any two of the three arguments.
The third one can always be inferred.
Usually x
and y
are given, but knowing x
and s
is enough to infer y
.
Examples
Addition of Numbers
Add two integers using +
:
def output = 1 + 2
//output> 3
Add an integer and a float using add
:
def output = add[1, 2.5]
//output> 3.5
Add two floats using full expression:
def output(x) = add(1.7, 2.8, x)
//output> 4.5
Add integer to a rational:
def output = 1 + rational[16][2, 3]
//output> 5/3
Addition of Time
Add time to a timestamp:
def output:tomorrow = datetime_now + ^Day[1]
def output:next_hour = datetime_now + ^Hour[1]
Add weeks to a date:
def output = 2022-12-24 + ^Week[2]
//output> 2023-01-07
Add seconds together:
def output = ^Second[1] + ^Second[2]
//output> 3
See Also
Any
View sourceAny(x)
Holds for any x
, where x
exists. (Any
functions as a wildcard.)
Example:
Integrity constraint that tests whether x
is of any type:
def R = (1, 3) ; (1, "foo")
ic any_ic {subset(R, (Int, Any) )}
approx_eq
View sourceapprox_eq(tolerance, x, y)
Approximate equality.
Use to compare scalar numbers and check if x
and y
are within the absolute tolerance (tolerance
) of each other.
Parameters
Parameter | Type | Description |
---|---|---|
tolerance | SignedInteger[#64] or FloatBinary[#64] | Tolerance of the approximation. A positive number. Must be grounded. |
x | Number | A valid number. Must be the same data type as y . Must be grounded. |
y | Number | A valid number. Must be the same data type as x . Must be grounded. |
Explanation
“approximately equal” is defined as number values being within the absolute tolerance (tolerance
)
of each other, or non-number values being equal.
The parameter tolerance
stands for the absolute tolerance and must be of type SignedInteger[#64]
or FloatBinary[#64]
.
Also, tolerance
must be a positive number; negative numbers will return false
x
and y
should be of the exact same data type.
For example, x
and y
can be of type FixedDecimal
or Rational
, but types must have the same bits and precision.
If x
or y
is not a number, approx_eq
defaults to eq
.
Examples
Approximate equality determined as true
:
def output = approx_eq(0.05, 0.1, 0.15)
//output> () // true
Approximate equality determined as false
:
def output = approx_eq(0.01, 0.1, 0.15)
//output> // false
See Also
approx_equal
View sourceapprox_equal(tolerance, R, S)
Approximate relational equality.
To hold true, the values in the last column of R
must be approximately equal to values in the last column of S
given the same key (prefix).
Parameters
Parameter | Type | Description |
---|---|---|
tolerance | SignedInteger[#64] or FloatBinary[#64] | A positive integer or float. Must be grounded. |
R | Relation | A relation with corresponding keys and last elements that can be compared to S . Must be grounded. |
S | Relation | A relation with corresponding keys and last elements that can be compared to R . Must be grounded. |
Explanation
Two relations R
and S
are considered “relationally approximately equal” when for each tuple (k..., x)
in S
there exists a tuple (k..., y)
in R
where x
and y
are considered approximately equal.
This approximate equality is symmetric and holds equally true when the places of R
and S
are swapped.
See approx_eq
for the details about approximate equality between two data values.
The parameter tolerance
stands for the absolute tolerance and must be of type SignedInteger[#64]
or FloatBinary[#64]
.
tolerance
must be a positive number; negative numbers will evaluate to false
.
Keys must match for approx_equal
to be true
.
All values of the last column in R
and S
must be of the exact same data type.
For example, the values can all be of type FixedDecimal
or Rational
, but types must have the same bits and precision.
Otherwise, approx_equal
evaluates to false
.
Note the correspondence between approx_equal
and equal
:
approx_equal(0, R, S)
if and
only if equal(R, S)
.
approx_equal
applies only to the values in the last column in R
and S
.
That is, if the values are not within tolerance
, approx_equal
will evaluate to false
even if other arguments in the relations are within tolerance
.
If full relation comparison functionality is required, see full_relation_approx_equal
.
Examples
Approximate relational equality determined as true
:
def salary1 = {("John", 10.0) ; ("Mary", 20.0); ("Paul", 17.0) ; ("Peter", 15.0) }
def salary2 = {("John", 9.99) ; ("Mary", 20.01); ("Paul", 17.0) ; ("Peter", 15.0) }
def output = approx_equal(0.1, salary1, salary2)
//output> () // true
Approximate relational equality determined as false
:
def salary1 = {("John", 10.0) ; ("Mary", 20.0); ("Paul", 17.0) ; ("Peter", 15.0) }
def salary2 = {("John", 11.0) ; ("Mary", 21.0); ("Paul", 17.0) ; ("Peter", 15.0) }
def output = approx_equal(0.1, salary1, salary2)
//output> // false
Approximate relational equality determined as false
because keys are different:
def salary1 = {("John", 10.0) ; ("Mary", 20.0); ("Paul", 17.0) ; ("Peter", 15.0) }
def salary3 = {("John", 9.99) ; ("Ben", 20.0); ("Paul", 17.0) ; ("Peter", 15.0) }
def output = approx_equal(0.1, salary1, salary3)
//output> // false
Approximate relational equality determined as false, even though the first arguments are within tolerance
:
def coordinates1 = (1.0, 2.0); (3.0, 6.0)
def coordinates2 = (1.0000001, 2.0); (2.9999999, 6.0000001)
def output = approx_equal(0.001, coordinates1, coordinates2)
//output> // false
See Also
full_relation_approx_equal
, approx_eq
, equal
, and eq
.
argmax
View sourceargmax[R]
argmax(R, am)
For a relation R
, find the tuples whose last elements are largest and return those tuples with the last element omitted.
Parameters
Parameter | Type | Description |
---|---|---|
R | Relation | A relation whose tuples contain key-value pairs. Must be grounded. |
am | Number | A tuple in R with the largest last element, with last element omitted. |
Explanation
If tuples in R
contain keys and values, argmax
returns all the keys for the largest value.
Typically, argmax
is used when the last elements of each tuple are numeric.
argmax
is typically used with relations whose shortest tuple has length two.
Note that, for all unary relations, argmax
results in a relation containing an empty tuple.
Examples
Find key for largest value of R
:
def R = {("A", 7.5); ("B", 8.6); ("C", 9.7); ("D", 7.5)}
def output(am) = argmax(R, am)
//output> "C"
Find key for largest value of R
where values are rationals:
def R = {("A", rational[64, 8, 3]); ("B", rational[64, 9, 7]); ("C", rational[64, 11, 4]); ("D", rational[64, 8, 3])}
def output = argmax[R]
//output> "C"
Find the teams with the largest aggregated salary:
def salary = {("Burrow", 11,515,044); ("Chase", 18,211,606); ("Allen", 77,289,124); ("Diggs", 45,466,111)}
def member = {("Bengals", "Burrow"); ("Bengals", "Chase"); ("Bills", "Allen"); ("Bills", "Diggs")}
def team = {"Bengals"; "Bills"}
def output = argmax[d in team: sum[salary[p] for p in member[d]]]
//output> "Bengals"
See Also
argmin
View sourceargmin[R]
argmin(R, am)
For a relation R
, find the tuples whose last elements are smallest and return those tuples with the last element omitted.
Parameters
Parameter | Type | Description |
---|---|---|
R | Relation | Source relation. Must be grounded. |
am | Any | A tuple in R with the smallest last element, with last element omitted. |
Explanation
If tuples in R
contain keys and values, argmin
returns all the keys for the smallest value.
Typically, argmin
is used when the last elements of each tuple are numeric.
argmin
is typically used with relations whose shortest tuple has length two.
Note that, for all unary relations, argmin
results in a relation containing an empty tuple.
Examples
Find key for smallest value of R
:
def R = {("A", 7.5); ("B", 8.6); ("C", 9.7); ("D", 7.5)}
def output(am) = argmin(R, am)
//output> "A"
// "C"
Find key for smallest value of R
where values are rationals:
def R = {("A", rational[64, 8, 3]); ("B", rational[64, 9, 7]); ("C", rational[64, 11, 4]); ("D", rational[64, 7, 3])}
def output = argmin[R]
//output> "B"
Find key for smallest value of R
with tuples of various arity:
def R = {("A", 7.5); ("B", 8.6); ("C", "W", 9.7); ("D", "X", 7.5)}
def output = argmin[R]
//output> "A"
// "D", "X"
Find the teams with the smallest aggregated salary:
def salary = {("Burrow", 11,515,044); ("Chase", 18,211,606); ("Allen", 77,289,124); ("Diggs", 45,466,111)}
def member = {("Bengals", "Burrow"); ("Bengals", "Chase"); ("Bills", "Allen"); ("Bills", "Diggs")}
def team = {"Bengals"; "Bills"}
def output = argmin[d in team: sum[salary[p] for p in member[d]]]
//output> "Bills"
See Also
arity
View sourcearity[R]
The arity of a relation. In some cases, it can be an over-approximation.
Arity is a higher-order relation that is always evaluated at compile-time.
Examples:
def output = arity[3]
//output> 1
def output = arity[{1; 2; 3}]
//output> 1
def output = arity[(1, 2)]
//output> 2
def output = arity[add]
//output> 3
def output = arity[{1; 2; (1,2)}]
//output> 1
// 2
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] = 2
def output = verbalize[true]
//output> "nullary"
def output = verbalize[1]
//output> "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, 3)
ic { 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 a run-time property of R
.
asin
View sourceasin[x]
asin(x, as)
Arcsine of x
. ac
is the arcsine of x
given in radians.
Parameters
Parameter | Type | Description |
---|---|---|
x | FloatBinary[#64] , SignedInteger[#64] | Sine of as . Must be grounded. |
as | FloatBinary[#64] | Arcsine of x . |
Explanation
Defined for x
between -1 and 1 (inclusive). The value of as
ranges from -π/2 to π/2.
Only 64-bit float and 64-bit integer values for x
are supported.
Arcsine is sometimes called “inverse sine.”
Examples
Calculate the arcsine of 1:
def output = asin[1]
//output> 1.5707963267948966
Calculate the arcsine of -.5 using full expression:
def output(x) = asin(-.5, x)
//output> -0.5235987755982989
Confirm that 1.5707963267948966 is the arcsine of 1:
def output = asin(1, 1.5707963267948966)
//output> () // true
See Also
asinh
View sourceasinh[x]
asinh(x, ash)
Hyperbolic arcsine. ash
is the hyperbolic arcsine of x
.
Parameters
Parameter | Type | Description |
---|---|---|
x | FloatBinary[#64] , SignedInteger[#64] | Hyperbolic sine of ash . Must be grounded. |
ash | FloatBinary[#64] | Hyperbolic arcsine of x . |
Explanation
Hyperbolic arcsine is sometimes called “inverse hyperbolic sine.”
Only 64-bit float and 64-bit integer values for x
are supported.
Examples
Calculate the hyperbolic arcsine of 10:
def output = asinh[10]
//output> 2.99822295029797
Calculate the hyperbolic arcsine of -1 using full expression:
def output(x) = asinh(-1, x)
//output> -0.881373587019543
Confirm that 2.99822295029797 is the hyperbolic arcsine of 10:
def output = asinh(10, 2.99822295029797)
//output> () // true
See Also
atan
View sourceatan[x]
atan(x, at)
Arctangent. at
is the arctangent of x
in radians.
Parameters
Parameter | Type | Description |
---|---|---|
x | FloatBinary[#64] , SignedInteger[#64] | Tangent of at . Must be gounded. |
at | FloatBinary[#64] | Arctangent of x . |
Explanation
Arctangent is sometimes called “inverse tangent.”
Only 64-bit float and 64-bit integer values for x
are supported.
Examples
Calculate the arctangent of π/4:
def output = atan[pi_float64/4]
//output> 0.6657737500283538
Convert degrees to radians and calculate arctangent using full expression:
def x = deg2rad[90]
def output(at) = atan(x, at)
//output> 1.0038848218538872
Confirm that 0.6657737500283538 is the tangent of π/4:
def output = atan(pi_float64/4, 0.6657737500283538)
//output> () // true
See Also
atan2
View sourceatan2[y, x]
atan2(y, x, at)
Arctangent. at
is the arctangent of the quotient y/x
in radians.
Parameters
Parameter | Type | Description |
---|---|---|
y | FloatBinary[#64] , SignedInteger[#64] , UnsignedInteger[#64] | coordinate of the 2D point . Must be gounded. |
x | UnsignedInteger[#64] , SignedInteger[#64] , FloatBinary[#64] | coordinate of the 2D point . Must be gounded. |
at | FloatBinary[#64] | Arctangent of x . |
Explanation
Arctangent is sometimes called “inverse tangent.”
The parameters x
and y
can be thought of as the and coordinates of the 2D point .
Examples
Calculate the arctangent of 50:
def output = atan2[100, 2.0]
//output> 1.550798992821746
See Also
atanh
View sourceatanh[x]
atanh(x, ath)
Hyperbolic arctangent. ath
is the hyperbolic arctangent of x
.
Parameters
Parameter | Type | Description |
---|---|---|
x | FloatBinary[#64] , SignedInteger[#64] | Hyperbolic tangent of ath . Must be grounded. |
ath | FloatBinary[#64] | Hyperbolic arctangent of x . |
Explanation
Hyperbolic arctangent is sometimes called “inverse hyperbolic tangent.”
Only 64-bit float and 64-bit integer values for x
are supported.
Examples
Calculate the hyperbolic arctangent of -.7:
def output = atanh[-.7]
//output> -0.8673005276940532
Calculate the hyperbolic arctangent of .7 using full expression:
def output(x) = atanh(.7, x)
//output> 0.8673005276940532
Confirm that -0.8673005276940532 is the hyperbolic arctangent of -.7:
def output = atanh(-.7, -0.8673005276940532)
//output> () // true
See Also
average
View sourceaverage[R]
average(R, m)
The average (arithmetic mean) of a relation R
.
average
is an alias for mean
.
For details, see the docstring for mean
.
bigint
View sourcebigint[i]
Create a BigInteger value from the given integer.
Examples:
string[factorial[bigint[50]]] = "30414093201713378043612608166064768844377641568960512000000000000"
bigint_int64_convert
View sourceConvert a BigInteger to an Int64.
Examples:
bigint_int64_convert[bigint[50]] = 50
bitwise_and
View sourcebitwise_and[x, y]
bitwise_and(x, y, z)
Bitwise and of two integers.
Parameters
Parameter | Type | Description |
---|---|---|
x | SignedInteger , UnsignedInteger | Left operand. Must be grounded. |
y | SignedInteger , UnsignedInteger | Right operand. Must be grounded. |
z | SignedInteger , UnsignedInteger | The bitwise and of x and y . |
Not all numeric values can be mixed with each other. The following combinations work:
x | y | z |
---|---|---|
SignedInteger , UnsignedInteger | Same as x . | Same as x . |
SignedInteger , UnsignedInteger | SignedInteger[#64] , UnsignedInteger[#32] | Same as x . |
Examples
Bitwise and of 3
and 2
:
def output = bitwise_and[3, 2]
//output> 2
Bitwise and of two unsigned integers using full expression:
def output(z) = bitwise_and(0x11100, 0x00101, z)
//output> 256
Bitwise and of unsigned and signed integers:
def output = bitwise_and[0x010b, -265]
//output> 3 // is an UnsignedInteger[#16]
See Also
bitwise_or
, bitwise_xor
, bitwise_left_shift
, bitwise_right_shift
, bitwise_unsigned_right_shift
, and bitwise_not
.
bitwise_left_shift
View sourcebitwise_left_shift[x, y]
bitwise_left_shift(x, y, z)
Bitwise left shift of an integer x
by y
bits.
Parameters
Parameter | Type | Description |
---|---|---|
x | SignedInteger , UnsignedInteger | Operand. Must be grounded. |
y | SignedInteger , UnsignedIntegere | Bits for left shift. Must be grounded. |
z | SignedInteger , UnsignedInteger | The bitwise left shift of x and y . |
Not all numeric values can be mixed with each other. The following combinations work:
x | y | z |
---|---|---|
SignedInteger , UnsignedInteger | Same as x . | Same as x . |
SignedInteger , UnsignedInteger | SignedInteger[#64] , UnsignedInteger[#32] | Same as x . |
Explanation
The type of shift done depends on the type of x
.
If x
is signed, bitwise_left_shift
performs a signed left shift (also known as an “arithmetic left shift”).
If x
is unsigned, bitwise_left_shift
performs an unsigned left shift (also known as a “logical left shift”).
Examples
Bitwise left shift of 8
by 1
bit:
def output = bitwise_left_shift[8, 1]
//output> 16
Bitwise left shift of 1
by 10
bits using full expression:
def output(z) = bitwise_left_shift(1, 10, z)
//output> 1024
Bitwise left shift of 0xf by 1
bit:
def output = bitwise_left_shift[0xF, 1]
//output> 30
Bitwise left shift of unsigned integer:
def output = bitwise_left_shift[uint[64, 4028], 1]
//output> 8056
See Also
bitwise_and
, bitwise_or
, bitwise_xor
, bitwise_right_shift
, bitwise_unsigned_right_shift
, and bitwise_not
.
bitwise_not
View sourcebitwise_not[x]
bitwise_not(x, z)
Bitwise not of an integer.
Parameters
Parameter | Type | Description |
---|---|---|
x | SignedInteger , UnsignedInteger | Operand. Must be grounded. |
z | SignedInteger , UnsignedInteger | The bitwise not of x . |
Not all numeric values can be mixed with each other. The following combinations work:
x | z | |
---|---|---|
SignedInteger , UnsignedInteger | Same as x . | Same as x . |
Examples
Bitwise not of -9
:
def output = bitwise_not[-9]
//output> 8
Bitwise not of 8
using full expression:
def output(z) = bitwise_not(8, z)
//output> -9
Bitwise not of 0x00011
:
def output = bitwise_not[0x00011]
//output> 4294967278
See Also
bitwise_and
, bitwise_or
, bitwise_xor
, bitwise_left_shift
, bitwise_right_shift
, and bitwise_unsigned_right_shift
.
bitwise_or
View sourcebitwise_or[x, y]
bitwise_or(x, y, z)
Bitwise or
of two integers.
Parameters
Parameter | Type | Description |
---|---|---|
x | SignedInteger , UnsignedInteger | Left operand. Must be grounded. |
y | SignedInteger , UnsignedInteger | Right operand. Must be grounded. |
z | SignedInteger , UnsignedInteger | The bitwise or of x and y . |
Not all numeric values can be mixed with each other. The following combinations work:
x | y | z |
---|---|---|
SignedInteger , UnsignedInteger | Same as x . | Same as x . |
SignedInteger , UnsignedInteger | SignedInteger[#64] , UnsignedInteger[#32] | Same as x . |
Examples
def output = bitwise_or[3, 2]
//output> 3
Bitwise or of 0x00011
and 0x11100
using full expression:
def output(z) = bitwise_or(0x00011, 0x11100, z)
//output> 69905
Bitwise xor of two unsigned integers:
def output = bitwise_or[uint[64, 1024], uint[64, 2048]]
//output> 3072
See Also
bitwise_and
, bitwise_xor
, bitwise_left_shift
, bitwise_right_shift
, bitwise_unsigned_right_shift
, and bitwise_not
.
bitwise_right_shift
View sourcebitwise_right_shift[x, y]
bitwise_right_shift(x, y, z)
Bitwise right shift of an integer x
by y
bits that preserves the sign.
Parameters
Parameter | Type | Description |
---|---|---|
x | SignedInteger , UnsignedInteger | Operand. Must be grounded. |
y | SignedInteger , UnsignedInteger | Bits for right shift. Must be grounded. |
z | SignedInteger , UnsignedInteger | The bitwise right shift of x and y . |
Not all numeric values can be mixed with each other. The following combinations work:
x | y | z |
---|---|---|
SignedInteger , UnsignedInteger | Same as x . | Same as x . |
SignedInteger , UnsignedInteger | SignedInteger[#64] , UnsignedInteger[#32] | Same as x . |
Examples
Bitwise right shift of 1024
by 1
bit:
def output = bitwise_right_shift[1024, 1]
//output> 512
Bitwise right shift of -1024
by 1
bit using full expression:
def output(z) = bitwise_right_shift(-1024, 1, z)
//output> -512
Bitwise right shift of unsigned integer by 2 bits:
def output = bitwise_right_shift[uint[64, 2048], 2]
//output> 512
See Also
bitwise_and
, bitwise_or
, bitwise_xor
, bitwise_left_shift
, bitwise_unsigned_right_shift
, and bitwise_not
.
bitwise_unsigned_right_shift
View sourcebitwise_unsigned_right_shift[x, y]
bitwise_unsigned_right_shift(x, y, z)
Bitwise unsigned right shift of an integer by y
bits.
Parameters
Parameter | Type | Description |
---|---|---|
x | SignedInteger , UnsignedInteger | Operand. Must be grounded. |
y | SignedInteger , UnsignedInteger | Bits for unsigned right shift. Must be grounded. |
z | SignedInteger , UnsignedInteger | The bitwise unsigned right shift of x and y . |
Not all numeric values can be mixed with each other. The following combinations work:
x | y | z |
---|---|---|
SignedInteger , UnsignedInteger | Same as x . | Same as x . |
SignedInteger , UnsignedInteger | SignedInteger[#64] , UnsignedInteger[#32] | Same as x . |
Examples
Bitwise unsigned right shift of 8
by 1
bit:
def output = bitwise_unsigned_right_shift[8, 1]
//output> 4
Bitwise unsigned right shift of -8
by 2
bits:
def output(z) = bitwise_unsigned_right_shift(-8, 2, z)
//output> 4611686018427387902
Bitwise unsigned right shift of unsigned integer by 3
bits:
def output = bitwise_unsigned_right_shift[uint[64, 8], 3]
//output> 1
See Also
bitwise_and
, bitwise_or
, bitwise_xor
, bitwise_left_shift
, bitwise_right_shift
, and bitwise_not
.
bitwise_xor
View sourcebitwise_xor[x, y]
bitwise_xor(x, y, z)
Bitwise xor (exclusive or) of two integers.
Parameters
Parameter | Type | Description |
---|---|---|
x | SignedInteger , UnsignedInteger | Left operand. Must be grounded. |
y | SignedInteger , UnsignedInteger | Right operand. Must be grounded. |
z | SignedInteger , UnsignedInteger | The bitwise xor of x and y . |
Not all numeric values can be mixed with each other. The following combinations work:
x | y | z |
---|---|---|
SignedInteger , UnsignedInteger | Same as x . | Same as x . |
SignedInteger , UnsignedInteger | SignedInteger[#64] , UnsignedInteger[#32] | Same as x . |
Examples
Bitwise xor of 3
and 2
:
def output = bitwise_xor[3, 2]
//output> 1 // is a SignedInteger[#64]
Bitwise xor of 0x00011
and 0x11100
using full expression:
def output(z) = bitwise_xor(0x00011, 0x11100, z)
//output> 69905
Bitwise xor of two unsigned integers:
def output = bitwise_xor[uint[64, 1024], uint[64, 2048]]
//output> 3072
See Also
bitwise_and
, bitwise_or
, bitwise_left_shift
, bitwise_right_shift
, bitwise_unsigned_right_shift
, and bitwise_not
.
Boolean
View sourceBoolean(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)
boolean_and
View sourceboolean_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)
boolean_not
View sourceboolean_not(x,y)
Negation(not
) operator for the Boolean
data type.
Example:
def output(x, y) = boolean_not(x, y) and boolean_false(x)
boolean_or
View sourceboolean_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)
bottom
View sourcebottom[k, R]
bottom(k, R, index, x...)
Select the bottom k
tuples of relation R
according to the sort order of R
and add enumeration.
Parameters
Parameter | Type | Description |
---|---|---|
R | Relation | Source relation. Must be grounded. |
k | Int | Number of tuples to sort from the bottom of R . Must be grounded. |
index | Int | The new enumeration index starting at 1. |
x... | Tuple | A tuple in R associated with the new index index . |
Explanation
bottom
is reverse_sort
restricted to the last k
tuples of R
.
bottom
puts the tuples of R
in lexicographical order and then limits the result to the last k
tuples.
The index indicates the tuples of R
in reverse order.
For details on lexicographical ordering — particularly across data types — see enumerate
.
Simlar to reverse_sort
, bottom
takes a relation R(x...)
and produces a relation with the tuples (index, x...)
,
where the first element of each tuple (index
) is an integer index that enumerates the bottom k
tuples
in the original relation R
.
Examples
Apply bottom
to a relation with arity-1 tuples:
def output = bottom[2, {'a'; 'b'; 'c'; 'd'}]
//output> (1, 'd')
// (2, 'c')
Apply bottom
to a relation with arity-2 tuples:
def R = {('a', 1); ('b', 2); ('c', 3); ('d', 4); ('e', 5)}
def output = bottom[3, R]
//output> 1, e, 5
// 2, d, 4
// 3, c, 3
See Also
top
, enumerate
, sort
, and reverse_sort
.
byte
View sourcebyte[str]
byte[str, i]
byte(str, i, b)
Indexes into a string at byte position i
, mapping each position i
to a byte b
, as a UInt8 value.
If a string contains Unicode characters, the byte at index i
might be only a partial character.
Be careful with your indexing logic.
Both i
and b
can be optionally bound externally. When only str
is bound, this is
the mapping from each index to its corresponding byte.
Examples: Indexing into a known byte index:
byte["abcd", 2] = 0x62
byte["中文例子", 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})
capture_group_by_index
View sourcecapture_group_by_index[regex, input_string, offset]
A set of capture groups, each of the form (index, substring)
, where index
is the capture group index, and substring
is the first regex match in input_string
, starting at the character index specified by offset
.
regex
can be a string or a pattern.
Offsets (character indexes) start at 1.
Example:
capture_group_by_index["(\\d+):(\\d+)",
"Appointment from 12:45 to 1:30",
19]
is equal to
{(1, "12"); (2, "45")}
capture_group_by_name
View sourcecapture_group_by_name[regex, input_string, offset]
A set of capture groups, each of the form (name, substring)
, where name
is the capture group name, and substring
is the first regex match in input_string
, starting at the character index specified by offset
.
regex
can be a string or a pattern.
Offsets (character indexes) start at 1.
Each capture group should have a unique name.
Example:
capture_group_by_name["(?<hour>\\d+):(?<minute>\\d+)",
"Appointment from 12:45 to 1:30",
19]
is equal to
(("hour","12"); ("minute","45"))
cart
View sourcecart[R, S]
R × S
Cartesian product.
Examples:
def output = 1 ✕ 2
//output> (1,2)
def output = {1; 2} ✕ {3; 4}
//output> (1,3)
// (1,4)
// (2,3)
// (2,4)
ceil
View sourceceil[x]
ceil(x, c)
Round up to the nearest integer.
Parameters
Parameter | Type | Description |
---|---|---|
x | Number | Number to be rounded up. Must be grounded. |
c | SignedInteger[#64] | Ceiling of x . |
Return type is the same as x
.
Explanation
For positive x
, ceil
rounds away from 0.
For negative x
, ceil
rounds toward 0.
Examples
Calculate ceil
for positive float:
def output = ceil[4.5]
//output> 5.0
Calculate ceil
for negative float using full expression:
def output(c) = ceil(-4.5, c)
//output> -4.0
Calculate ceil
for rational:
def output = ceil[rational[64, 8, 3]]
//output> 3/1
See Also
floor
, floor_to_int
, trunc
, trunc_to_int
, and round
.
char
View sourcechar[str]
char[str, i]
char(str, i, c)
Indexes into a string at (Int) position i
, mapping each index i
to the i
-th character, c
.
Since this is indexed using character positions, the characters will always be whole Unicode characters.
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 is
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})
Char
View sourceChar(x)
Holds if x
is of type Char
, which has a Unicode character as its value and is specified with single quotes.
Examples:
Integrity constraint that tests whether x
is of type Char
:
def R = 't'
ic mychar_ic(x in R)
Char(x)
}
Schema defined in a relation using Char
:
def myrelation(x in Char, y in Int) {
x = 'a' and y = 123
}
def output = myrelation
//output> (a, 123)
clamp
View sourceclamp[low, high, value]
clamp(low, high, value, clamped)
Limit value
to a range between low
and high
.
The parameter clamped
contains the “clamped” result.
Parameters
Parameter | Type | Description |
---|---|---|
low | Same as value . | Lower bound. Must be grounded. |
high | Same as value . | Upper bound. Must be grounded. |
value | Number | Value to be clamped. Must be grounded. |
clamped | Same as value | value limited to between low and high . |
Explanation
The resulting value clamped
is equivalant to value
as long as it is within the lower and upper bounds.
If value
lies outside of these bounds, then clamped
will take on the value of the bound that is closest to value
.
In mathematical terms, this reads:
For example, if low
and high
are of type Float
, value
should also be of type Float
.
Note that relations never contain duplicates.
If value
is a relation with multiple values lower than low
(or higher than high
), clamp[low, high, value]
will contain only once the value low
(high
).
Examples
Clamp relation with integer values:
def low = 1
def high = 4
def value = {-4; 2; 7}
def output = clamp[low, high, value]
//output> 1
// 2
// 4
Clamp relation with rationals. Note that relations never contain duplicates, thus only low and high values are included in output
.
def low = rational[64, 7, 27]
def high = rational[64, 26, 27]
def value = {rational[64, 1, 27]; rational[64, 6, 27]; rational[64, 31, 27]}
def output = clamp[low, high, value]
//output> 7/27
// 26/27
See Also
concat
View sourceconcat[val1, val2]
String concatenation of two arbitrary values
Example:
concat["a", "b"] = "ab"
concat["a", 'b'] = "ab"
concat['a', "b"] = "ab"
concat['a', 'b'] = "ab"
concat["a_", 1] = "a_1"
concat[1, 3.14] = "13.14"
contains
View sourcecontains(s, substring)
True iff the second argument, substring
, occurs as a substring in the first argument, s
.
Examples:
contains("Rel is cool!", "Rel is cool!") // true
contains("Rel is cool!", " is coo") // true
contains("Rel is cool!", 'c') // true
contains("Rel is cool!", 'C') // false
cos
View sourcecos[x]
cos(x, c)
Cosine of of x
, where x
is an angle given in radians.
Parameter | Type | Description |
---|---|---|
x | FloatBinary[#64] , SignedInteger[#64] | Angle in radians. Must be grounded. |
c | FloatBinary[#64] | Cosine of x . |
Explanation
Defined for non-infinite x
.
Only 64-bit float and 64-bit integer values for x
are supported.
Examples
Calculate the cosine of π/6:
def output = cos[pi_float64/6]
//output> 0.8660254037844387
Calculate the cosine of π/4 using full expression:
def output(x) = cos(pi_float64/4, x)
//output> 0.7071067811865476
Confirm that 0.5000000000000001 is the cosine of π/3:
def output = cos(pi_float64/3, 0.5000000000000001)
//output> () // true
See Also
cosh
View sourcecosh[x]
cosh(x, ch)
Hyperbolic cosine. ch
is the hyperbolic cosine of x
.
Parameters
Parameter | Type | Description |
---|---|---|
x | FloatBinary[#64] , SignedInteger[#64] | Hyperbolic angle. Must be grounded. |
ch | FloatBinary[#64] | Hyberbolic cosine of x . |
Explanation
Only 64-bit float and 64-bit integer values for x
are supported.
Examples
Calculate the hyperbolic cosine of 1:
def output = cosh[1]
//output> 1.5430806348152437
Calculate the hyperbolic cosine of -7 using full expression:
def output(x) = cosh(-7, x)
//output> 548.317035155212
Confirm that 1.5430806348152437 is the hyperbolic cosine of 1:
def output = cosh(1, 1.5430806348152437)
//output> () // true
See Also
cot
View sourcecot[x]
cot(x, ct)
Cotangent. ct
is the cotangent of x
, where x
is in radians.
Parameters
Parameter | Type | Description |
---|---|---|
x | FloatBinary[#64] , SignedInteger[#64] | Angle in radians. Must be grounded. |
ct | FloatBinary[#64] | Cotangent of x . |
Explanation
Only 64-bit float and 64-bit integer values for x
are supported.
Examples
Calculate the cotangent of π/4:
def output = cot[pi_float64/4]
//output> 1.0000000000000002
Convert degrees to radians and calculate cotangent using full expression:
def x = deg2rad[90]
def output(t) = cot(x, t)
//output> 6.123233995736766e-17
Confirm that 1.0000000000000002 is the cotangent of π/4:
def output = cot(pi_float64/4, 1.0000000000000002)
//output> () // true
See Also
count
View sourcecount[R]
count(R, n)
Count the number n
of tuples contained in the relation R
.
Parameters
Parameter | Type | Description |
---|---|---|
R | Relation | A general relation. Must be grounded. |
n | Integer | Number of tuples in R . |
Explanation
The relation count
contains the higher-order tuple (R, n)
if R
is a relation with n
tuples.
The form count[R]
is generally used to count the number of tuples in a relation R
.
The form count(R, n)
is generally used to test whether R
contains n
tuples.
If R
is empty, count[R]
is false
.
To get 0 instead, use left_override
, as in count[R] <++ 0
.
Examples
Count the number of tuples in a relation called employees
:
def employees = {
("jane", 12);
("tran", 24);
("miguel", 36)
}
def output = count[employees]
//output> 3
Count a singleton relation:
def output = count[5]
//output> 1
Test if employees
contains three tuples:
def output = count(employees, 3)
//output> () // true
See Also
argmax
, argmin
, average
, bottom
, top
, first
, last
, max
, min
, mode
, and product
.
csv_string
View sourcecsv_string[R]
The string representation of relation that encodes as CSV using the configuration relation R
.
Required keywords are:
: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(:COLUMN_NAME, pos, val) Optional keywords::syntax
: A relation containing syntax configuration. The following options can be specified::header
: A relation with(Int, RelName)
pairs, specifying the column names in the file, where theInt
indices indicate the column order, and the column name is provided as a Symbol (of typeRelName
). This option overrides the default (or existing) header names.:header_row
: AnInt
that specifies the row where the file header is. The column names are specified by the content of that row, if they are not defined using the header option above. The values -1 and 0 indicate that no header is present and the system creates column names for you.:datarow
: AnInt
that specifies the row from where to start parsing values into relations.:missingstrings
: One or multipleString
values that should be interpreted as missing values. By default, only empty fields are considered missing.:delim
: An ASCIIChar
that delimits individual fields while parsing. Defaults to','
.:quotechar
: An ASCIIChar
that signals a “quoted” field while parsing. Defaults to'"'
.:escapechar
: An ASCIIChar
used to “escape”quotechar
s and otherescapechar
s within a quoted (e.g., text) field. Defaults to'\\'
.
Example using default CSV syntax
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 config[:data] = csv_data
def output = csv_string[config]
Example using custom CSV syntax
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 config[:data] = csv_data
def config[:syntax, :delim] = '\t'
def config[:syntax, :quotechar] = '_'
def output = csv_string[config]
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, 2, 10; 2, 1, 11; 3, 1, 12; 3, 2 ,13)(pos..., v)
def config[:data] = csv_data
def output = csv_string[config]
Note that when using compound keys pos...
, they are required to contain no specialized values.
This mean no RelNames like :id
or any other specialized value like #(1)
are allowed.
See Also
current_transaction_id
View sourcecurrent_transaction_id
The Transaction ID of the current transaction as an unsigned 128-bit integer.
This is comparable to Snowflake CURRENT_TRANSACTION
, SQL Server CURRENT_TRANSACTION_ID
,
and PostgreSQL txid_current
.
date_add
View sourcedate_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]]
//output> 2021-10-11
date_day
View sourcedate_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
date_dayname
View sourcedate_dayname[d]
Name of week-day (a String, e.g., Friday
)
Example:
def t = parse_date["2014-01-31", "Y-m-d"]
def output = date_dayname[t]
//output> "Friday"
date_dayofquarter
View sourcedate_dayofquarter[d]
Day of quarter
Example:
def d = parse_date["2014-01-31", "Y-m-d"]
date_dayofquarter[d] = 31
date_dayofweek
View sourcedate_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
date_dayofweekofmonth
View sourcedate_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
date_dayofyear
View sourcedate_dayofyear[d]
Day of year
Example:
def t = parse_date["2014-01-31", "Y-m-d"]
def output = date_dayofyear[t]
//output> 31
date_daysinmonth
View sourcedate_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] = 31
def d2 = parse_date["2014-02-11", "Y-m-d"]
date_daysinmonth[d2] = 28
def d = parse_date["2016-02-11", "Y-m-d"]
date_daysinmonth[d] = 29
date_isleapyear
View sourcedate_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]
//output> // false
def output = date_isleapyear[leap]
//output> () // true
date_monthname
View sourcedate_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"
date_quarterofyear
View sourcedate_quarterofyear[d]
Quarter to year
Example:
def d = parse_date["2014-01-31", "Y-m-d"]
date_quarterofyear[d] = 1
date_subtract
View sourcedate_subtract[date, period]
date - period
Subtract a Period from a Date, giving another Date.
Example:
def d = parse_date["2021-09-21", "Y-m-d"]
def output = date_subtract[d, ^Day[1000]]
//output> 2018-12-26
date_week
View sourcedate_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
date_year
View sourcedate_year[d]
Year of a Date, as an integer.
Example:
date_year[parse_date["2020-05-22", "Y-m-d"]]
2020
^Year[date_year[parse_date["2020-05-22", "Y-m-d"]]]
(2020 years,)
dates_period_days
View sourcedates_period_days[date1, date2]
The difference in days between two dates date2
and date1
as a Day
data type.
Example:
def days = dates_period_days[
2022-05-12,
2022-05-15
]
ic { equal(days, ^Day[3]) }
datetime_add
View sourcedatetime_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]]
//output> 2022-01-01T01:00:00.000Z
def output = datetime_add[dt, ^Month[13]]
//output> 2022-02-01T01:00:00.000Z
def output = datetime_add[dt, ^Hour[1000]]
//output> 2021-02-11T17:00:00.000Z
datetime_day
View sourcedatetime_day(dt, tz, d)
Compute the day of the month d
of a timestamp dt
in the timezone tz
.
Parameters
Parameter | Type | Description |
---|---|---|
dt | DateTime | Date and time of the current transaction. Must be grounded. |
tz | String | Time zone. Must be grounded. |
d | Int | Day of the month. |
Explanation
Specifying the timezone tz
is required because the day of the month, d
, depends on the timezone you’re in.
Note that the timezone needs to be stated and can’t be infered.
In particular, it is not possible to infer all valid timezones tz
from a given timestamp dt
and day d
.
Examples
Get the day of the month of a given timestamp in different timezones:
def dt = parse_datetime["2024-01-01 01:00:00", "Y-m-d H:M:S"]
def output = datetime_day[dt, "Europe/Berlin"]
//output> 1
def output = datetime_day[dt, "America/New_York"]
//output> 31
def output = datetime_day[dt, "-03:00"]
//output> 31
See Also
date_day
, datetime_year
, datetime_month
, datetime_week
, and datetime_hour
.
datetime_day_UTC
View sourcedatetime_day_UTC(dt, d)
Compute the day of the month d
of a timestamp dt
assuming the UTC timezone.
Parameters
Parameter | Type | Description |
---|---|---|
dt | DateTime | Date and time of the current transaction. Must be grounded. |
d | Int | Day of the month. |
Examples
Get the day of the month in the UTC timezone for a timestamp that is defined in the Asia/Kathmandu timezone:
def dt = parse_datetime["2024-01-01 01:45 Asia/Kathmandu", "Y-m-d H:M Z"]
def output = datetime_day_UTC[dt]
//output> 31
See Also
datetime_month_UTC
, datetime_week_UTC
, datetime_day
, and date_day
.
datetime_dayname
View sourcedatetime_dayname[t, tz]
Name of week-day (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"
datetime_dayofquarter
View sourcedatetime_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
datetime_dayofweek
View sourcedatetime_dayofweek[dt, tz]
Day of week (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"] = 5
datetime_dayofweek[dt, "UTC"] = 4
datetime_dayofweekofmonth
View sourcedatetime_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
datetime_dayofyear
View sourcedatetime_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"] = 90
datetime_dayofyear[dt, "+00:00"] = 89
datetime_daysinmonth
View sourcedatetime_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"] = 31
datetime_daysinmonth[t, "-03:00"] = 28
datetime_hour
View sourcedatetime_hour(dt, tz, h)
Compute the hour of the day h
of a timestamp dt
in the timezone tz
.
Parameters
Parameter | Type | Description |
---|---|---|
dt | DateTime | Date and time of the current transaction. Must be grounded. |
tz | String | Time zone. Must be grounded. |
h | Int | Hour of the day. |
Explanation
Specifying the timezone tz
is required because the hour of the day, h
, depends on the timezone you’re in.
Note that the timezone needs to be stated and can’t be infered.
In particular, it is not possible to infer all valid timezones tz
from a given timestamp dt
and hour h
.
Examples
Get the hour of the day of a given timestamp in different timezones:
def dt = parse_datetime["2024-01-01 01:00:00", "Y-m-d H:M:S"]
def output = datetime_hour[dt, "Europe/Berlin"]
//output> 2
def output = datetime_hour[dt, "America/New_York"]
//output> 20
def output = datetime_hour[dt, "-03:00"]
//output> 22
See Also
datetime_hour_UTC
View sourcedatetime_hour_UTC(dt, h)
Compute the hour h
of a timestamp dt
assuming the UTC timezone.
Parameters
Parameter | Type | Description |
---|---|---|
dt | DateTime | Date and time of the current transaction. Must be grounded. |
h | Int | Hour of the day. |
Examples
Get the hour of the day in the UTC timezone for a timestamp that is defined in the Asia/Kathmandu timezone:
def dt = parse_datetime["2024-01-01 01:45 Asia/Kathmandu", "Y-m-d H:M Z"]
def output = datetime_hour_UTC[dt]
//output> 20
See Also
datetime_isleapyear
View sourcedatetime_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"]
//output> // false
def dtleap = parse_datetime["2016-01-31 01:00 +03:00", "YYYY-mm-dd HH:MM zzzz"]
def output = datetime_isleapyear[dtleap, "+00:00"]
//output> () // true
datetime_minute
View sourcedatetime_minute(dt, tz, m)
Compute the minute part of a timestamp dt
in the timezone tz
.
Parameters
Parameter | Type | Description |
---|---|---|
dt | DateTime | Date and time of the current transaction. Must be grounded. |
tz | String | Time zone. Must be grounded. |
m | Int | Minute. |
Explanation
Specifying the timezone tz
is required because the minute, m
, depends on the timezone you’re in.
For instance, some time zones like “Asia/Kathmandu” are shifted by 30 or 45 minutes with respect to UTC time.
Note that the timezone needs to be stated and can’t be infered.
In particular, it is not possible to infer all valid timezones tz
from a given timestamp dt
and minute m
.
Examples
Get the minute of given timestamp in different timezones:
def dt = parse_datetime["2024-01-01 01:00:00", "Y-m-d H:M:S"]
def output = datetime_minute[dt, "America/New_York"]
//output> 0
def output = datetime_minute[dt, "Asia/Kathmandu"]
//output> 45
See Also
datetime_minute_UTC
View sourcedatetime_minute_UTC(dt, m)
Compute the minute m
of a timestamp dt
assuming the UTC timezone.
Parameters
Parameter | Type | Description |
---|---|---|
dt | DateTime | Date and time of the current transaction. Must be grounded. |
m | Int | Minute. |
Examples
Get the minute in the UTC timezone for a timestamp that is defined in the Asia/Kathmandu timezone:
def dt = parse_datetime["2024-01-01 01:45 Asia/Kathmandu", "Y-m-d H:M Z"]
def output = datetime_minute_UTC[dt]
//output> 0
See Also
datetime_month
View sourcedatetime_month(dt, tz, m)
Compute the month m
of a timestamp dt
in the timezone tz
.
Parameters
Parameter | Type | Description |
---|---|---|
dt | DateTime | Date and time of the current transaction. Must be grounded. |
tz | String | Time zone. Must be grounded. |
m | Int | Month. |
Explanation
Specifying the timezone tz
is required because the month, m
, depends on the timezone you’re in.
Note that the timezone needs to be stated and can’t be infered.
In particular, it is not possible to infer all valid timezones tz
from a given timestamp dt
and month m
.
Examples
Get the month of a given timestamp in different timezones:
def dt = parse_datetime["2021-01-01 01:00:00", "Y-m-d H:M:S"]
def output = datetime_month[dt, "Europe/Berlin"]
//output> 1
def output = datetime_month[dt, "America/New_York"]
//output> 12
def output = datetime_month[dt, "-03:00"]
//output> 12
See Also
datetime_month_UTC
View sourcedatetime_month_UTC(dt, m)
Compute the month m
of a timestamp dt
assuming the UTC timezone.
Parameters
Parameter | Type | Description |
---|---|---|
dt | DateTime | Date and time of the current transaction. Must be grounded. |
m | Int | Month. |
Examples
Get the month in the UTC timezone for a timestamp that is defined in the Asia/Kathmandu timezone:
def dt = parse_datetime["2024-01-01 01:45 Asia/Kathmandu", "Y-m-d H:M Z"]
def output = datetime_month_UTC[dt]
//output> 12
See Also
datetime_monthname
View sourcedatetime_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"
datetime_now
View sourcedatetime_now(dt)
The current time dt
at the beginning of the transaction.
Parameters
Parameter | Type | Description |
---|---|---|
dt | DateTime | Date and time of the current transaction. |
Explanation
datetime_now
is used to get current UTC time.
The resulting DateTime
value reflects the start time of the current transaction.
Installed logic that makes use of datetime_now
may be updated with each new transaction.
In particular, datetime_now
cannot be used to capture the date and time that a model was installed.
For instance, if you install the relation def my_time = datetime_now
in a model,
then each time you query def output = my_time
, a new DateTime
value is returned.
However, if you insert datetime_now
into a base relation,
the time is preserved until a future read/write transaction updates it.
For example, def insert:my_time = datetime_now
inserts the current date and time
into a base relation named my_time
.
Repeatedly querying def output = my_time
always returns the same DateTime
value.
Examples
Get the current UTC time by simply querying for datetime_now
.
Example:
def output = datetime_now
//output> 2023-10-10T18:52:35.263Z
datetime_quarterofyear
View sourcedatetime_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
datetime_second
View sourcedatetime_second(dt, s)
Compute the second s
of a timestamp dt
.
Parameters
Parameter | Type | Description |
---|---|---|
dt | DateTime | Date and time of the current transaction. Must be grounded. |
s | Int | Second. |
Explanation
No timezone is required because the second, s
, of a timestamp, dt
, is independent of the timezone.
This is in contrast to datetime_minute
and datetime_hour
, where the timezone information is required.
Examples
Get the second of given timestamp:
def dt = parse_datetime["2024-01-01 01:02:03", "Y-m-d H:M:S"]
def output = datetime_second[dt]
//output> 3
See Also
datetime_subtract
View sourcedatetime_subtract[dt, period]
dt - period
Subtract a Period from a DateTime, giving 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]]
//output> 2020-11-20T09:00:00.000Z
datetime_to_nanoseconds
View sourcedatetime_to_nanoseconds[dt]
Convert datetime to nanoseconds since the epoch. Assumes dt
is in UTC.
datetime_week
View sourcedatetime_week(dt, tz, w)
Compute the ISO week number (opens in a new tab) w
of a timestamp dt
in the timezone tz
.
Parameters
Parameter | Type | Description |
---|---|---|
dt | DateTime | Date and time of the current transaction. Must be grounded. |
tz | String | Time zone. Must be grounded. |
w | Int | ISO week number. |
Explanation
Specifying the timezone tz
is required because the calendar week, w
, depends on the timezone you’re in.
Note that the timezone needs to be stated and can’t be infered.
In particular, it is not possible to infer all valid timezones tz
from a given timestamp dt
and week w
.
Examples
Get the ISO week of a given timestamp in different timezones:
def dt = parse_datetime["2024-01-01 01:00:00", "Y-m-d H:M:S"]
def output = datetime_week[dt, "Europe/Berlin"]
//output> 1
def output = datetime_week[dt, "America/New_York"]
//output> 52
def output = datetime_week[dt, "-03:00"]
//output> 52
See Also
datetime_week_UTC
View sourcedatetime_week_UTC(dt, w)
Compute the ISO week number (opens in a new tab) w
of a timestamp dt
assuming the UTC timezone.
Parameters
Parameter | Type | Description |
---|---|---|
dt | DateTime | Date and time of the current transaction. Must be grounded. |
w | Int | ISO week number. |
Examples
Get the week number in the UTC timezone for a timestamp that is defined in the Asia/Kathmandu timezone:
def dt = parse_datetime["2024-01-01 01:45 Asia/Kathmandu", "Y-m-d H:M Z"]
def output = datetime_week_UTC[dt]
//output> 52
See Also
datetime_month_UTC
, datetime_day_UTC
, datetime_week
, and date_week
.
datetime_year
View sourcedatetime_year(dt, tz, y)
Compute the year y
of a timestamp dt
in the timezone tz
.
Parameters
Parameter | Type | Description |
---|---|---|
dt | DateTime | Date and time of the current transaction. Must be grounded. |
tz | String | Time zone. Must be grounded. |
y | Int | Year. |
Explanation
Specifying the timezone tz
is required because the calendar year, y
, depends on the timezone you’re in.
Note that the timezone needs to be stated and can’t be infered.
In particular, it is not possible to infer all valid timezones tz
from a given timestamp dt
and year y
.
Examples
Get the year of a given timestamp in different timezones:
def dt = parse_datetime["2021-01-01 01:00:00", "Y-m-d H:M:S"]
def output = datetime_year[dt, "Europe/Berlin"]
//output> 2021
def output = datetime_year[dt, "America/New_York"]
//output> 2020
def output = datetime_year[dt, "-03:00"]
//output> 2020
See Also
datetime_year_UTC
View sourcedatetime_year_UTC(dt, y)
Compute the year y
of a timestamp dt
assuming the UTC timezone.
Parameters
Parameter | Type | Description |
---|---|---|
dt | DateTime | Date and time of the current transaction. Must be grounded. |
y | Int | Year. |
Examples
Get the year in the UTC timezone for a timestamp that is defined in the Asia/Kathmandu timezone:
def dt = parse_datetime["2024-01-01 01:45 Asia/Kathmandu", "Y-m-d H:M Z"]
def output = datetime_year_UTC[dt]
//output> 2023
See Also
datetimes_period_milliseconds
View sourcedatetimes_period_milliseconds[dt1, dt2]
The difference between two datetimes, dt2 - dt1
, as a Millisecond
data type.
In other words, equal to the milliseconds time period between dt1
and dt2
— which when added to dt1
gives dt2
.
Example:
def output = datetimes_period_milliseconds[
unix_epoch,
parse_datetime["2021-03-19 11:00:40", "YYYY-mm-dd HH:MM:SS"]
]
ic {rel:base:Millisecond(output)}
Day
View sourceDay[n]
DEPRECATED
This function is deprecated and should be avoided. It will be removed soon.
Please use the Day constructor, ^Day
, instead.
Create a period of n
days.
decimal
View sourcedecimal[n, digits, v]
The n
-bit decimal value with digits
precision from number value v
.
n
must be among #8, #16, #32, #64, and #128. The precision digits
must be:
- between #0 and #2 if
n
= #8 - between #0 and #4 if
n
= #16 - between #0 and #9 if
n
= #32 - between #0 and #18 if
n
= #64 - between #0 and #32 if
n
= #128
Note that the value v * 10^digits
must be encodable with n
-bits.
Examples:
decimal[#64, #2, 3.14156] = 3.14
empty(decimal[#64, #20, 1000])
empty(decimal[#8, #2, 2])
decimal_bit_length
View sourcedecimal_bit_length[decimal]
The bit length of a fixed-point decimal number.
Example:
def g = parse_decimal[#64, #2, "3.14"]
decimal_bit_length[g] = 64
decimal_int_convert
View sourcedecimal_int_convert[x]
Conversion from n
-bit fixed-point decimal with d
precision to n
-bit int.
If the argument is not equivalent to an int, decimal_int_convert
returns false
.
Example:
decimal_int_convert[decimal[#32, #2, 3.00]] = 3
decimal_int_convert[decimal[#32, #2, 3.20]] = false
decimal_precision
View sourcedecimal_precision[decimal]
The precision of a fixed-point decimal number.
Example:
def g = parse_decimal[#64, #2, "3.14"]
decimal_precision[g] = 2
decode_base16
View sourcedecode_base16[encoded_str]
Decodes the base-16 encoded string to string, as per rfc4648 specifications.
Encoding/decoding specifications are found at https://datatracker.ietf.org/doc/html/rfc4648 (opens in a new tab).
Example:
def output = decode_base16["48656C6C6F21"]
//output> "Hello!"
def output = decode_base16["E4BDA0E5A5BD"]
//output> "你好"
decode_base32
View sourcedecode_base32[encoded_str]
Decodes the base-32 encoded string to string, as per rfc4648 specifications.
Encoding/decoding specifications are found at https://datatracker.ietf.org/doc/html/rfc4648 (opens in a new tab).
Example:
def output = decode_base32["JBSWY3DPEE======"]
//output> "Hello!"
def output = decode_base32["4S62BZNFXU======"]
//output> "你好"
decode_base64
View sourcedecode_base64[encoded_str]
Decodes the base-64 encoded string to string, as per rfc4648 specifications.
Encoding/decoding specifications are found at https://datatracker.ietf.org/doc/html/rfc4648 (opens in a new tab).
Example:
def output = decode_base64["SGVsbG8h"]
//output> "Hello!"
def output = decode_base64["5L2g5aW9"]
//output> "你好"
default_value
View sourcedefault_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]
//output> (1, 321)
// (2, 42)
// (3, 123)
// (4, 42)
See Also
deg2rad
View sourcedeg2rad[d]
deg2rad(d, r)
Convert degrees to radians.
Parameters
Parameter | Type | Description |
---|---|---|
d | Float , Int | r in degrees. Must be grounded. |
r | Float | d in radians. |
Examples
Convert 180
degrees to radians:
def output = deg2rad[180]
//output> 3.141592653589793
Convert -90
degrees to radians using full expression:
def output = deg2rad[-90]
//output> -1.5707963267948966
denominator
View sourcedenominator[x]
Denominator of a rational-like number.
Examples:
denominator[rational[64, 1, 3]] = 3
denominator[rational[64, 1, 100]] = 100
denominator[rational[64, 1, 100] + rational[64, 1, 3]] = 300
denominator[parse_decimal[#64, #2, "3.14"]] = 100
denominator[parse_decimal[#64, #5, "3.14159"]] = 10000
denominator[5] = 1
describe
View sourcedescribe[R]
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, 2020-01-01)
(:count, 4)
(:mode_freq, 1)
(:min, 2020-01-01)
(:max, 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)
despecialize
View sourcedespecialize[sv]
despecialize(sv, v)
Maps a specialized value sv
to the value v
.
Specialized values are used for schema information. Non-specialized values are used for storing the “actual” data.
Example:
def output = despecialize[#(55)]
//output> 55
def output = despecialize[:hello]
//output> "hello"
To verify the despecialization, one can write
def output = equal(despecialize[#(int[8, 0])], int[8, 0])
//output> () // true
diff
View sourcediff[R, S]
Set difference (complement): removes the tuples of S
from R
, if present.
Example:
def output = diff[{1;2;3;4} , {1;3} ]
//output> 2
// 4
divide
View sourcedivide[x, y]
divide(x, y, q)
x / y
Division of two numbers.
Parameters
Parameter | Type | Description |
---|---|---|
x | Number | Numerator. Must be grounded. |
y | Number | Denominator. Must be grounded. |
q | Number | Quotient x / y . |
Not all numeric types can be combined with one another.
The following combinations work (note that for some type combinations, a y
of zero is
mathematically undefined, so the result is false
(empty)):
x | y | q |
---|---|---|
FloatBinary | Same as x | Same as x |
Rational , FixedDecimal | Non-zero same as x | Same as x |
SignedInteger , UnsignedInteger | SignedInteger , UnsignedInteger | FloatBinary[#64] |
FloatBinary[#64] | Number | FloatBinary[#64] |
Number | FloatBinary[#64] | FloatBinary[#64] |
SignedInteger , UnsignedInteger | SignedInteger[#64] | FloatBinary[#64] |
SignedInteger[#64] | SignedInteger , UnsignedInteger | FloatBinary[#64] |
FloatBinary | SignedInteger[#64] | Same as x |
SignedInteger[#64] | FloatBinary | Same as y |
FixedDecimal | Non-zero SignedInteger , UnsignedInteger | Same as x |
SignedInteger , UnsignedInteger | Non-zero FixedDecimal | Same as y |
Rational | Non-zero SignedInteger | Rational with the larger bitsize of x and y |
SignedInteger | Non-zero Rational | Rational with the larger bitsize of x and y |
Explanation
In contrast to add
and subtract
, x
and y
need to be grounded and specified by the user.
Specifying only x
and q
or only y
and q
is not sufficient as the system can’t compute the inverse.
Examples
Divide two integers using /
:
def output = 24 / 2
//output> 12.0
Divide two rationals using /
:
def output = rational[64, 8, 3] / rational[64, 5, 2]
//output> 16/15
Divide one float by another using divide
:
def output = divide[8.4, 2.1]
//output> 4.0
Divide a rational by an integer using full expression:
def output(x) = divide(rational[16, 8, 3], 2, x)
//output> 4/3
docstring
View sourcedocstring[:R]
The docstring of a relation as a string.
Example:
doc"The number 0." def zero = 0
def output = docstring[:zero]
//output> "The number 0."
domain
View sourcedomain[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)}]
//output> (1, 'a')
// (2, 'b')
// (3, 'c')
double_metaphone
View sourcedouble_metaphone[string_value]
double_metaphone_alt[string_value]
Double Metaphone is an improvement
of metaphone
that considers spelling particularities in a number of other languages.
double_metaphone
and double_metaphone_alt
returns an encoding of
the phonetic representation of string_value
. For many strings, double_metaphone
and
double_metaphone_alt
returns the very same encoding. However, it may differs based on the
spelling in a non-English language.
string_value
could be any arbitrary long string
Examples:
@inline def dm[string] = double_metaphone[string] ; double_metaphone_alt[string]
def output = dm["Smith"]
//output> sm0
def output = dm["Smythe"]
//output> sm0
// xmt
def output = dm["Christina"]
//output> krstn
def output = dm["Cristine"]
//output> krstn
def output = dm["I like Music"]
//output> ilkm
def output = dm["i loak Museek"]
//output> ilkm
def output = dm["RelationalAI"]
//output> rlxnl
def output = dm["rellationalleAI"]
//output> rlxnl
encode_base16
View sourceencode_base16[input_str]
Encodes the given string(input_str
) to base16-encoded string, as per rfc4648 specifications.
Encoding/decoding specifications are found at https://datatracker.ietf.org/doc/html/rfc4648 (opens in a new tab).
Examples:
def output = encode_base16["Hello!"]
//output> 48656C6C6F21
def output = encode_base16["你好"]
//output> "E4BDA0E5A5BD"
encode_base32
View sourceencode_base32[input_str]
Encodes the given string(input_str
) to base32-encoded string, as per rfc4648 specifications.
Encoding/decoding specifications are found at https://datatracker.ietf.org/doc/html/rfc4648 (opens in a new tab).
Example:
def output = encode_base32["Hello!"]
//output> "JBSWY3DPEE======"
def output = encode_base32["你好"]
//output> "4S62BZNFXU======"
encode_base64
View sourceencode_base64[input_str]
Encodes the given string(input_str
) to base64-encoded string, as per rfc4648 specifications.
Encoding/decoding specifications are found at https://datatracker.ietf.org/doc/html/rfc4648 (opens in a new tab).
Example:
def output = encode_base64["Hello!"]
//output> "SGVsbG8h"
def output = encode_base64["你好"]
//output> "5L2g5aW9"
ends_with
View sourceends_with(s, suffix)
True if and only if the given string, s
, ends with the given suffix, suffix
.
The suffix can be a string of characters or a single character.
Example:
ends_with("abc", "c") // true
ends_with("abc", 'c') // true
ends_with("abc", "abc") // true
ends_with("abc", "C") // false
ends_with("abc", "ab") // false
ends_with("abc", "abcd") // false
Entity
View sourceEntity(x)
Holds if x
is an entity. This is an alias for Hash
.
Example:
Integrity constraint specifying that mymodule
always contains an entity:
def mymodule:f = 1
ic my_entity_ic(x) { mymodule(x) implies Entity(x) }
enumerate
View sourceenumerate[R]
enumerate(R, index, x...)
Enumerate the tuples in the relation R
from 1 to count[R]
.
Parameters
Parameter | Type | Description |
---|---|---|
R | Relation | Relation to be enumerated. Must be grounded. |
index | Int | The new enumeration index starting at 1. |
x... | Tuples | A tuple in R associated with the new index index . |
Explanation
enumerate
takes a relation R(x...)
and produces a relation with the tuples (index, x...)
, where index
is an integer running from 1 to the number of tuples in the relation (count[R]
).
enumerate
supports relations that contain tuples with different data type signatures.
This includes relations with tuples of various lengths, or arities. For example, {(1, 2); (1, 2, 3)}
can be enumerated together.
Enumerating across data types is also supported. For example, enumerating the three tuples in {"a"; 1; 2.0}
.
The enumeration is deterministic meaning enumerating the same tuples will always produce the same result.
The details of the enumeration logic are described below.
Lexicographical Order
Lexicographical order of the tuples is determined by first sorting them according to their data schema, according to the following rules:
- Tuples are first ordered by the data types in the first column, then second, and so on.
- Tuples with no data in the current column come first. For example,
(Int)
comes before(Int, Int)
. - Within each column, types are put in alphabetical order. For example,
Char
precedesDate
, which precedesFloatBinary
. - If types have parameters, they are ordered by parameters. For example,
FloatBinary[#32]
precedesFloatBinary[#64]
, and so on.
After the schemas of the tuples are sorted, the tuples with the same schema are sorted based on the actual values in the tuples, according to the following rules:
- Tuples are first sorted by the data values in the first column, then second, and so on.
- Tuples are ordered based on the intrinsic order of the data type.
- Numeric data types: Sorting numerically. For example,
1
comes before2
. - Text-based data types:
Char
andString
are sorted “asciibetically”, which means that digits and punctuation marks come before letters, and uppercase letters come before lowercase letters; for example, “Z” precedes “a”. - Date-based data types:
Date
andDateTime
are sorted so that older timestamps come first.
- Numeric data types: Sorting numerically. For example,
Examples
Enumerate an arity-1 relation:
def sample = {'a'; 'b'; 'c'}
def output = enumerate[sample]
//output> (1, 'a')
// (2, 'b')
// (3, 'c')
//first column is index
Enumerate an arity-2 relation (alphabetical on first column):
def sample = {
("phone", 45);
("laptop", 89);
("memory", 100)
}
def output(index, x...) = enumerate(sample,index, x...)
//output> (1,"laptop",89)
// (2,"memory",100)
// (3,"phone",45)
Just as with aggregations, it is possible to enumerate separately per group.
In the following example, the enumeration is grouped by the group-by variable x
,
which iterates over the values in the first column of sample
.
def sample = { (:g, 'a'); (:g, 'b'); (:g, 'c'); (:h, 'd'); (:h, 'e'); (:h, 'f') }
def output[x] = enumerate[sample[x]]
//output> (:g, 1, 'a')
// (:g, 2, 'b')
// (:g, 3, 'c')
// (:h, 1, 'd')
// (:h, 2, 'e')
// (:h, 3, 'f')
Enumerate a relation containing various tuple lengths and types:
def sample = {
2; 3;
"a"; "b";
(1, 3); (1, 10);
}
def output = enumerate[sample]
//output> (1, 2)
// (2, 3)
// (3, 1, 3)
// (4, 1, 10)
// (5, "a")
// (6, "b")
Here you can see the impact of sorting the data schemas first: tuples of the form (Int)
come before tuples of the form (Int, Int)
.
Because the sorting of data type per column is more important than the length of the tuples, the tuples of the form (String)
come after (Int, Int)
tuples, making ("b")
the tuple with the largest index.
See Also
sort
and reverse_sort
.
epoch_milliseconds
View sourceepoch_milliseconds[dt]
Milliseconds since Epoch time, as a value of type Int64
.
eq
View sourceeq(x, y)
x = y
Equality between scalar (single) values, such as integers, strings, symbols. (For equality between relations, use equal
.)
Examples:
1 = 1
istrue
.:a = :a
istrue
"a" = "a"
istrue
2 = 2.0
isfalse
1 = "a"
isfalse
equal
View sourceequal(R, S)
F ≡ G
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.
erf
View sourceerf[x]
The error function of x
.
External link: https://en.wikipedia.org/wiki/Error_function (opens in a new tab)
Examples:
erf[2] = 0.9953222650189527
erf[-0.5] = -0.5204998778130465
erfinv
View sourceerfinv[x]
The inverse error function of x
.
External link: https://en.wikipedia.org/wiki/Error_function#Inverse_functions (opens in a new tab)
Examples:
erfinv[0.1] = 0.08885599049425769
erfinv[-0.5] = -0.4769362762044699
erfinv[erf[1]] = 1.0
escape_regex_metachars
View sourceescape_regex_metachars(string, escaped_string)
Escape the necessary regular expression metacharacters in string
such that
escaped_string
can be used as a regular expression and have none of its
characters interpreted as metacharacters.
Example:
def ere = escape_regex_metachars["."]
def output = regex_match_all[ere, "abc.123"]
will only give
{(4, ".")}
since .
is escaped and is not treated as a metacharacter.
export_csv
View sourceexport_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 URI (location and name) where the data will be exported. Exporting to local files is not currently supported.
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(:COLUMN_NAME, pos, val):integration
: A relation containing storage integration configuration.:syntax
: A relation containing syntax configuration.:partition_size
: An int specifying at what estimated file size in MB the produced CSV file should be split into partitions. For example, if the exported CSV file is estimated to have a size of 1GB, with:partition_size=100
it will be exported into 10 partitions of roughly 100MB each. Set:partition_size=0
to suppress partitioning even for very large exports at the cost of export performance. By default,:partition_size=0
is used.:compression
: The algorithm that is used to compress the CSV output file. We only supportgzip
at the current stage.
Example using default CSV schema and syntax and exporting to Azure storage integration using a SAS token:
def integration[:provider] = "azure"
def integration[:credentials, :azure_sas_token] = "<azure_sas_token>"
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, "azure://<account_name>.blob.core.windows.net/container/file.csv");
(:data, csv_data)
]
Example using a custom CSV schema:
def csv_syntax[:delim] = ';'
def csv_syntax[:quotechar] = '_'
def export = export_csv[
(:path, "azure://<account_name>.blob.core.windows.net/container/file.csv");
(:data, csv_data);
(:syntax, csv_syntax)
]
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, 2, 10; 2, 1, 11; 3, 1, 12; 3, 2 ,13)(pos..., v)
def export = export_csv[
(:path, "azure://<account_name>.blob.core.windows.net/container/file.csv");
(:data, csv_data)
]
Note that when using compound keys pos...
, they are required to contain no specialized values.
This mean no RelNames like :id
or any other specialized value like #(1)
are allowed.
export_json
View sourceexport_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"
}
]
}
factorial
View sourcefactorial[x]
Factorial of x.
Defined for non-negative x
.
The result is promoted to at least 64-bits.
If x
is up to 64-bits, factorial
is defined for values up to 20 (inclusive).
If x
is Int128
, factorial
is defined for values up to 33 (inclusive).
If x
is UInt128
, factorial
is defined for values up to 34 (inclusive).
filepos
View sourcefilepos[v]
DEPRECATED
This function is deprecated and should be avoided. It will be removed soon.
Please use the FilePos constructor, ^FilePos
, instead.
Creates a FilePos representing position v
in a file.
FilePos
View sourceFilePos(x)
Brings the data type relation FilePos
from the module rel:base
into the global namespace.
For more details, see the rel:base:FilePos
docstring.
filepos_value
View sourcefilepos_value[fp]
DEPRECATED
This function is deprecated and should be avoided. It will be removed soon.
Please use the FilePos constructor, ^FilePos
, instead.
Retrieves the numeric position represented by a FilePos.
first
View sourcefirst[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)]
//output> 1
// 4
def output = first[(1, 2, 3); (4, 5); 6]
//output> 1
// 4
// 6
def output = first[("a", 1); (2, 3)]
//output> 2
// "a"
FixedDecimal
View sourceFixedDecimal(nbits, ndecimals, x)
Holds if x
is of type FixedDecimal
with a bit size of nbits
and ndecimals
decimal precision.
nbits
and ndecimals
are specialized integers.
Examples:
Integrity constraint that tests whether x
is a FixedDecimal
with a bit size of #64
and #4
decimal precision:
def R = decimal[#64, #4, pi_float64]
ic float_type_check(x in R) {
FixedDecimal(#64, #4, x)
}
Query to check whether x
is a FixedDecimal
with a bit size of #64
and #4
decimal precision.
def R = {decimal[#64, #4, pi_float64]; decimal[#64, #10, pi_float64]}
def output(x) = R(x) and FixedDecimal(#64, #4, x)
//output> 3.1416
FixedDecimal_spread
View sourceFixedDecimal_spread[mode, R, val]
FixedDecimal_spread(mode, R, value, x..., spread)
Spread value
to the tuples in relation R
as decimals, either evenly or proportionally to their
weight, which is the last element in each tuple.
Parameter | Type | Description |
---|---|---|
mode | RelName | :even or :ratio . |
R | Relation | Source relation. Must be grounded. |
value | FixedDecimal | Decimal to be divided among tuples as spread . |
x... | Tuple | A tuple in R . |
spread | FloatBinary[#64] | Spread associated with x... . |
Explanation
FixedDecimal_spread
takes a relation R(x...)
and produces a relation with the
tuples (x..., spread)
where the last element of each tuple (spread
)
is a spread of value
distributed among tuples.
When mode
is :even
, spread
is value
divided evenly among tuples.
When mode
is :ratio
, spread
is value
divided proportionally to a tuple’s
weight — the last element in each tuple.
In contrast to int_spread_by_even
and int_spread_by_ratio
, here spread
is a decimal, 10^(-d)
, where d
is the
number of digits used in value
.
For example, if value
is 3.140
, the smallest unit to spread will be 0.001
.
FixedDecimal_spread
is empty if value
is negative.
Examples
Spread 3.14
among three tuples:
def R = {("Atlanta", 50);
("Seattle", 80);
("San Francisco", 10)}
def output = FixedDecimal_spread[:even, R, decimal[#64, #3, 3.14]]
//output> Atlanta, 50, 1.047
// San Francisco, 10, 1.047
// Seattle, 80, 1.046
Spread 10.5
among three tuples using :ratio
:
def R = {("Atlanta", 10);
("Seattle", 80);
("San Francisco", 10)}
def output = FixedDecimal_spread[:ratio, R, decimal[#64, #3, 10.5]]
//output> Atlanta, 50, 1.05
// San Francisco, 10, 1.05
// Seattle, 80, 8.4
Spread 88.55
among three tuples using full expression:
def R = {("Miles Davis", 65); ("Jimmy Smith", 76); ("Ornette Coleman", 85)}
def output(x...) = FixedDecimal_spread(:ratio, R, decimal[#64, #3, 88.55], x...)
//output> Jimmy Smith, 29.778
// Miles Davis, 25.468
// Ornette Coleman, 33.304
Spread using group-by:
def R = {
("Seattle", "Washington", 1);
("San Francisco", "California", 0.4);
("Los Angeles", "California", 0.6)
}
def amount = {
("Washington", decimal[#64, #3, 50]);
("California", decimal[#64, #3, 100.0])
}
def output[state] = FixedDecimal_spread[
:ratio,
(city, v : R(city, state, v)),
amount[state]
]
//output> California, Los Angeles, 60.0
// California, San Francisco, 40.0
// Washington, Seattle, 50.0
See Also
FixedPoint
View sourceFixedPoint(x)
Holds if x
is a fixed point number.
Parameters
Parameter | Type | Description |
---|---|---|
x | FixedPoint | A fixed point value. |
Explanation
A FixedPoint
can be created with decimal
, as shown in the examples below.
Examples
def R = decimal[#64, #4, pi_float64]
ic fixedpoint_type_check(x in R) {
FixedPoint(x)
}
def R = 5; decimal[#64, #4, pi_float64]
def output(x) = R(x) and FixedPoint(x)
//output> 3.1416
See Also
FixedSizeInteger
View sourceFixedSizeInteger(x)
Holds if x
is a fixed size integer (signed or unsigned).
Parameters
Parameter | Type | Description |
---|---|---|
x | FixedSizeInteger | A fixed size integer value. |
Explanation
A FixedSizeInteger
can be created with int
or uint
, or using an int or uint literal, as shown in the examples below.
Examples
def R = int[8, 5]; uint[8, 5]
ic fixedsize_int_type_check(x in R) {
FixedSizeInteger(x)
}
def R = 5; 0x05; rational[16, -5, -7]
def output(x) = R(x) and FixedSizeInteger(x)
//output> 5; 0x05
See Also
FixedSizeRational
View sourceFixedSizeRational(x)
Holds if x
is a fixed size rational (signed or unsigned).
Parameters
Parameter | Type | Description |
---|---|---|
x | FixedSizeRational | A fixed size rational value. |
Explanation
A FixedSizeRational
can be created with rational
, as shown in the examples below.
Examples
def R = rational[16, -5, -7]
ic fixedsize_rational_type_check(x in R) {
FixedSizeRational(x)
}
def R = int[8, 5]; uint[8, 5]; rational[16, -5, -7]
def output(x) = R(x) and FixedSizeRational(x)
//output> 5//7
See Also
float
View sourcefloat[n, v]
The n-bit floating point value from the number v
.
n
must be among 16, 32, and 64.
Examples:
float[64, 3.0] = 3.0
float[16, 3.14156] = 3.14
empty(float[11, 3.14])
float_int_convert
View sourcefloat_int_convert[x]
Conversion from float to int.
If the argument is not equivalent to an int, float_int_convert
returns false
. (See trunc_to_int
, floor_to_int
for general conversion.)
Example:
float_int_convert[3.0] = 3
float_int_convert[3.2] = false
float64
View sourcefloat64[v]
The 64-bit floating point value from the number v
, which must be a float.
FloatBinary
View sourceFloatBinary(#nbits, x)
Holds if x
is an `nbits’ floating point number.
Parameters
Parameter | Type | Description |
---|---|---|
#nbits | #(Int) | A specialized integer (must be a valid bit size). |
x | FloatBinary | A float value. |
Examples
Integrity constraint that tests if x
is a 32-bit float (will throw if x
is not a 32-bit Float):
def R = float[32, 1.321]
ic float_type_check(x in R) {
FloatBinary(#32, x)
}
See Also
Float
, Float32
, and Float64
.
Floating
View sourceFloating(nbits, x)
DEPRECATED
This relation is deprecated and should be avoided. It will be removed soon.
Please use FloatBinary
instead. Note that FloatBinary
takes a specialized integer
for nbits
.
Holds if x
is an nbits' floating point number.
Float(x)is a shorthand that holds if
x` is a 64-bit float.
Example:
Integrity constraint that tests if x
is a 32-bit float (will throw if x
is not a 32-bit Float):
def R = float[32, 1.321]
ic float_type_check(x in R) {
Floating(32, x)
}
FloatingPoint
View sourceFloatingPoint(x)
Holds if x
is a floating point number.
Parameters
Parameter | Type | Description |
---|---|---|
x | FloatingPoint | A floating point value. |
Explanation
A FloatingPoint
can be created with float
or using a float literal, as shown in the examples below.
Examples
def R = float[32, 1.321]
ic float_type_check(x in R) {
FloatingPoint(x)
}
def R = 5; 1.321
def output(x) = R(x) and FloatingPoint(x)
//output> 1.321
See Also
floor
View sourcefloor[x]
floor(x, f)
Round down to the nearest integer toward negative infinity.
Parameters
Parameter | Type | Description |
---|---|---|
x | Number | Number to be rounded down. Must be grounded. |
f | Number | Floor of x . |
Return type is the same as x
.
Explanation
For positive x
, floor
rounds toward 0.
For negative x
, floor
rounds away from 0.
Examples
Calculate floor for decimal:
def output = floor[4.569]
//output> 4.0
Calculate floor for negative decimal using full expression:
def output(f) = floor(-4.569, f)
//output> -5.0
Calculate floor for positive rational:
def output = floor[rational[64, 8, 3]]
//output> 2/1
See Also
floor_to_int
, ceil
, trunc
, trunc_to_int
, and round
.
floor_divide
View sourcefloor_divide[x, y]
floor_divide(x, y, q)
Division of two numbers, rounding the result to the nearest integer toward negative infinity.
Parameters
Parameter | Type | Description |
---|---|---|
x | Number | Numerator. Must be grounded. |
y | Number | Denominator. Must be grounded. |
q | Number | Largest integer less than or equal to x / y . |
Not all numeric values can be mixed with each other. The following combinations work:
x | y | q |
---|---|---|
SignedInteger[#64] | SignedInteger[#64] | SignedInteger[#64] |
SignedInteger[#64] | FloatBinary[#64] | FloatBinary[#64] |
FloatBinary[#64] | SignedInteger[#64] , FloatBinary[#64] | FloatBinary[#64] |
Rational | SignedInteger[#64] | SignedInteger[#64] |
FixedDecimal | SignedInteger[#64] | Same as x |
Explanation
Largest integer less than or equal to x/y
.
Computes x/y
rounded towards negative infinity.
floor_divide
maps the pair x
, y
to q
, which is the floored quotient x/y
.
Similar to divide
and in contrast to add
and subtract
, x
and y
need to be grounded and specified by the user.
Specifying only x
and q
or only y
and q
is not sufficient, because the system can’t compute the inverse.
Is false
(empty) when y = 0
for integer arguments.
Examples
Use floor division to divide a postiive integer by a positive integer:
def output = floor_divide[5, 2]
//output> 2
Use floor division with full expression to divide a negative integer by a positive integer:
def output(q) = floor_divide(-5, 2, q)
//output> -3
Use floor division to divide a float by an integer:
def output = floor_divide[5.1, 2]
//output> 2.0
Confirm that floor_division[R]
is empty
when y
= O:
def output = empty(floor_divide[5.1, 0])
//output> () // true
floor_to_int
View sourcefloor_to_int[x]
floor_to_int(x, f)
Convert float to integer using floor.
Parameters
Parameter | Type | Description |
---|---|---|
x | Float | Float to be converted to integer using floor. Must be grounded. |
f | Int | Floor of x . |
Explanation
For positive x
, floor_to_int
rounds toward 0.
For negative x
, floor_to_int
rounds away from 0 toward negatve infinity.
Examples
Convert float to integer:
floor_to_int[3.1]
//output> 3
Convert negative float to integer using full expression. Note that rounding goes away from 0 toward negative infinity.
def output(f) = floor_to_int(-3.1, f)
//output> -4
Returns false
because x
is an integer:
def output = floor_to_int[3]
//output> // false
See Also
floor
, ceil
, trunc
, trunc_to_int
, and round
.
format_date
View sourceformat_date[d, format]
A string where the Date d
is formatted according to format
.
Example:
def d = parse_date["2018-06-12", "Y-m-d"]
def output = format_date[d, "Y-mm-d"]
//output> 2018-06-12
For details on the format parameter, see the Julia documentation for Dates.DateFormat
(opens in a new tab).
format_datetime
View sourceformat_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"]
//output> "2018-03-11 01:00 EST"
For details on the format parameter, see the Julia documentation for Dates.DateFormat
(opens in a new tab).
formula_card_est
View sourceformula_card_est[R]
The cardinality estimate of a given relational abstraction R
as estimated by the
physical query optimizer. The 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)]
frequency
View sourcefrequency[R, elem]
frequency(R, elem, freq)
frequency[R]
Find the frequency freq
of elem
in the set of all
last elements of tuples in the relation R
.
Parameters
Parameter | Type | Description |
---|---|---|
R | Relation | A general relation. Must be grounded. |
elem | Any | Element whose frequency will be found. |
freq | Number | The frequency of elem . |
Explanation
If elem
is omitted, frequency[R]
finds the frequency of each element.
Examples
Find the frequency of a single value:
def example = {(1, "a"); (2, "b"); (3, 123); (4, 12.5); (3, "b")}
def output = frequency[example, "b"]
//output> 2
Find the frequency of all values:
def example = {(1, "a"); (2, "b"); (3, 123); (4, 123); (5, "b"); (6, "b")}
def output = frequency[example]
//output> 123, 2
// "a", 1
// "b", 3
full_relation_approx_equal
View sourcefull_relation_approx_equal(tolerance, R, S)
Approximate relational equality of the entire relation.
To hold true, all tuples (and the values they hold) in R
and S
must be approximately equal to each other.
Parameter | Type | Description |
---|---|---|
tolerance | SignedInteger[#64] or FloatBinary[#64] | A positive integer or float. |
R | Relation | A relation whose arguments can be compared to S . |
S | Relation | A relation whose arguments can be compared to R . |
Explanation
Two relations R
and S
are considered “fully relationally approximately equal” when there exists for each tuple in R
a tuple in S
that is considered approximately equal (and vice versa).
Two tuples are considered approximately equal if each element within one tuple is approximately equal to the element in the other tuple which is located at the same position. This implies tuples that are approximately equal need to have the same length.
See approx_eq
for the details about approximate equality between two data values.
The parameter tolerance
stands for the absolute tolerance and must be of type SignedInteger[#64]
or FloatBinary[#64]
.
tolerance
must be a positive number; negative numbers will return false
.
full_relation_approx_equal
is quite slow and should not be used for large data sets.
Example
Approximate relational equality determined as true
:
def coordinates1 = (1.0, 2.0); (3.0, 6.0)
def coordinates2 = (1.0000001, 2.0); (2.9999999, 6.0000001)
def output = full_relation_approx_equal(0.001, coordinates1, coordinates2)
//output> () // true
Approximate relational equality determined as false:
def coordinates1 = (1.0, 2.0); (3.0, 6.0)
def coordinates2 = (1.0000001, 2.05); (2.9999999, 6.0000001)
def output = full_relation_approx_equal(0.001, coordinates1, coordinates2)
//output> // false
See Also
approx_equal
, approx_eq
, equal
, and eq
.
function
View sourcefunction(R)
Holds if R
is a function.
Parameter | Type | Description |
---|---|---|
R | Relation | A general relation. Must be grounded. |
Given a relation R
, function(R)
is true
if R
is a function and false
if not.
Functions are relations where values — the last elements of tuples — are uniquely determined by the keys — the initial elements of tuples.
That is, a relation R(x, y, z)
is a function if and only if each initial set of elements x, y
— the “key” —
map to only one value each for z
.
For example, the relation {(1, “one”); (2, “two”)}
is a function, but the relation
{(1, “one”); (1, “uno”); (2, “two”); (2, “dos”)}
is not a function, because the keys 1
and 2
have multiple values.
Similarly, R{(1, 2, 3); (1, 3, 5)}
is a function but R{(1, 2, 3); (1, 2, 4)}
is not a function, because multiple tuples start with (1, 2)
.
This understanding of function is also consistent with mathematical functions — as with sin
or power
/^
— where the argument(s) of the function map to one value.
In this sense, mathematical functions are relations with a functional dependency.
The arguments, x...
, and value, v
, of the function map to the tuples (x..., y)
in the relation.
For mathematical function, the domain of x...
is usually continuous and unbound.
Examples
Evaluates to true
:
def output = function({(1, 2); (2, 5)})
//output> () // true
Evaluates to false
:
def output = function({(1, 2); (1, 3)})
//output> // false
Arity-3 function that evaluates to true
:
def output = function({(1, 2, 3) ; (1, 3, 4)})
//output> () // true
Integrity constraint ensuring that R
is a function:
ic R_is_a_function { function(R) }
See Also
domain
and default_value
.
geometric_mean
View sourcegeometric_mean[R]
geometric_mean(R, gm)
The geometric mean of the last element of each tuple in a relation R
.
Parameters
Parameter | Type | Description |
---|---|---|
R | Relation | A relation whose tuples contain numeric data types. Must be grounded. |
gm | SignedInteger , FloatBinary | The geometric mean of R . |
Explanation
The geometric mean of a relation R
that contains n
tuples is the n
-th root
of the product of the last elements in each tuple.
geometric_mean
aggregates over all tuples in R
.
Tuples in R
can have different lengths, and the length may vary from tuple to tuple.
Tuples with a non-numeric last element are ignored.
Note that geometric_mean
groups the tuples by the data type of the last element.
This may cause unexpected results when used in relations with values of mixed types.
Typically, geometric_mean
is used when the last elements of each tuple have the same type
If R
is empty, geometric_mean[R]
is false
(empty).
Use <++
(left override) if you need a specific value for the case where R
is empty.
Examples
Calculate geometric mean for R
:
def R = {("A", 1); ("B", 3); ("C", 5); ("D", 7); ("E", 9)}
def output = geometric_mean[R]
//output> 3.936283427035352
Calculate geometric mean for R
using full expression:
def R = {("A", 7.5); ("B", 8.6); ("C", 9.7); ("D", 7.5)}
def output(gm) = geometric_mean(R, gm)
//output> 8.276527798701737
See Also
mean
, harmonic_mean
, weighted_mean
, mode
, max
, min
, sum
, and product
.
harmonic_mean
View sourceharmonic_mean[R]
harmonic_mean(R, hm)
The harmonic mean (hm
) of the last elements of each tuple in a relation R
.
Parameters
Parameter | Type | Description |
---|---|---|
R | Relation | A relation whose tuples contain numeric data types. Must be grounded. |
hm | Number | The harmonic mean of R . |
Explanation
The harmonic mean of a relation R
is the reciprocal of
the arithmetic mean of the reciprocals of the last elements in each tuple.
harmonic_mean
aggregates over all tuples in R
.
Tuples in R
can have different lengths, and the length may vary from tuple to tuple.
Tuples with a non-numeric last element are ignored.
Note that harmonic_mean
groups the tuples by the data type of the last element.
This may cause unexpected results when used in relations with values of mixed types.
Typically, harmonic_mean
is used when the last elements of each tuple have the same type.
If R
is empty, harmonic_mean[R]
is false
(empty).
Use <++
(left override) if you need a specific value for the case where R
is empty.
Examples
Calculate the harmonic mean of R
:
def output = harmonic_mean[{('a',1); ('b',2); ('a',3); ('b',4); ('c',5); ('d',6}]
2.44897959184
Calculate the harmonic mean of R
using the full expression:
def R = {("A", 7.5); ("B", 8.6); ("C", 9.7); ("D", 7.5)}
def output(hm) = harmonic_mean(R, hm)
//output> 8.229800388043014
Find the harmonic mean for relation with tuples of various lengths:
def R = {(10); (2, 30); (3, 50, 2)}
def output = harmonic_mean[R]
//output> 4.736842105263158
See Also
geometric_mean
, weighted_mean
, mean
, mode
, max
, min
, sum
, and product
.
hash
View sourcehash[R]
hash(R, x..., h)
Hash each of the tuples in the relation and add it as a new column in the result.
Parameters
Parameter | Type | Description |
---|---|---|
R | Relation | Relation to be hashed. Must be grounded. |
x... | Tuples | A tuple in R associated with hash . |
h | Hash | A 128-bit HashValue index. |
Explanation
hash
takes a relation R(x...)
and produces a relation R(x..., h)
where the last element of the relation, h
, is a 128-bit HashValue
that is the result of hashing all elements in the tuple x...
and combining them into one value.
hash
is identical to hash128
.
Examples
Hash a single value:
def output = hash['a']
//output> a, 59209653874858713274180299714158372840
Hash a relation with tuples that have multiple elements:
def sample = {('a', 1); ('b', 2); ('c', 3)}
def output = hash[sample]
//output> a, 1, 218658623352236411286898175739604563355
// b, 2, 183357509907040413044473069762065340376
// c, 3, 153679601071624610141668476986592179913
Hash a relation using full expression:
def sample = {('a', 1); ('b', 2); ('c', 3)}
def output(x..., h) = hash(sample, x..., h)
//output> a, 1, 218658623352236411286898175739604563355
// b, 2, 183357509907040413044473069762065340376
// c, 3, 153679601071624610141668476986592179913
Confirm that identical tuples in different relations hash to the same value:
def R = (:a, 1); (:b, 2)
def S = (:a, 1); (:b, 2)
def output = equal[hash[R], hash[S]]
//output> () // true
See Also
hash_value_uint128_convert
, murmurhash3f
, and murmurhash3f_with_seed
.
Hash
View sourceHash(x)
Holds if x
is a RelationalAI HashValue generated by hash128
.
Examples:
Integrity constraint that tests whether x
is Hash (will throw if x
is not Hash):
def R = (9, "a")
def my_hash = hash128[R]
//three value relation with hash value as third value
ic hash_type_check{
subset(my_hash, (Any, Any, Hash))
}
Defines Hash as schema for a relation:
def R = (9, "a")
def my_hash = hash128[R]
def hashed_relation(x in Hash) = my_hash(_, _, x)
def output = hashed_relation
//output> -107770920621774551289984725953057040743
hash128
View sourcehash128[R]
hash128(R, x..., h)
Hash each of the tuples in the relation and add it as a new column in the result.
Parameters
Parameter | Type | Description |
---|---|---|
R | Relation | Relation to be hashed. Must be grounded. |
x... | Tuple | A tuple in R associated with hash . |
h | Hash | A 128-bit HashValue index. |
Explanation
hash128
takes each tuple x...
in R
and produces a relation (x..., h)
where the last element of the relation, h
, is a 128-bit HashValue
that is the result of hashing all elements in the tuple x...
and combining them into one value.
Examples
Hash a single value:
def output = hash128['a']
//output> a, 59209653874858713274180299714158372840
Hash a relation with tuples that have multiple elements:
def sample = {('a', 1); ('b', 2); ('c', 3)}
def output(x..., h) = hash128(sample, x..., h)
//output> a, 1, 218658623352236411286898175739604563355
// b, 2, 183357509907040413044473069762065340376
// c, 3, 153679601071624610141668476986592179913
Hash a relation using full expression:
def sample = {('a', 1); ('b', 2); ('c', 3)}
def output(x..., h) = hash128(sample, x..., h)
//output> a, 1, 218658623352236411286898175739604563355
// b, 2, 183357509907040413044473069762065340376
// c, 3, 153679601071624610141668476986592179913
Confirm that identical tuples in different relations hash to the same value:
def R = (:a, 1); (:b, 2)
def S = (:a, 1); (:b, 2)
def output = equal[hash128[R], hash128[S]]
//output> () // true
See Also
hash_value_uint128_convert
, murmurhash3f
, and murmurhash3f_with_seed
.
haversine
View sourcehaversine[r, x1, y1, x2, y2]
haversine(r, x1, y1, x2, y2, hs)
The great circle distance of two points, and , on a sphere of radius , using the Haversine formula. The two points are specified by their latitude and longitude in radians.
Parameters
Parameter | Type | Description |
---|---|---|
x1 | FloatBinary[#64] , SignedInteger[#64] , UnsignedInteger[#64] | coordinate of the 2D point . Must be gounded. |
y1 | FloatBinary[#64] , SignedInteger[#64] , UnsignedInteger[#64] | coordinate of the 2D point . Must be gounded. |
x2 | FloatBinary[#64] , SignedInteger[#64] , UnsignedInteger[#64] | coordinate of the 2D point . Must be gounded. |
y2 | FloatBinary[#64] , SignedInteger[#64] , UnsignedInteger[#64] | coordinate of the 2D point . Must be gounded. |
r | FloatBinary[#64] , SignedInteger[#64] , UnsignedInteger[#64] | radius of sphere. Must be grounded. |
hs | UnsignedInteger[#64] , SignedInteger[#64] , FloatBinary[#64] | Haversine of and on sphere of radius . |
Examples
Calculate the haversine of (10, 0) and (0, 0) on sphere of radius π/2:
def output = haversine[10, 0, 0, 0, pi_float64/2]
//output> 15.707963267948964
Calculate the haversine of (10, 10) and (-10, 0) on sphere of radius 2π using full expression:
def output(hs) = haversine(10, 10, -10, 0, 2*pi_float64, hs)
//output> 7.897244441795649
Hour
View sourceHour[n]
DEPRECATED
This function is deprecated and should be avoided. It will be removed soon.
Please use the Hour constructor, ^Hour
, instead.
Create a period of n
hours.
iff
View sourceF iff G
F ⇔ G
If and only if (boolean equivalence), for boolean (arity 0, true or false) arguments F and G.
implies
View sourceF implies G
F ⇒ G
G ⇐ F
Logical implication, for boolean (arity 0, true or false) arguments F and G.
int
View sourceint[n, v]
The n
-bit signed integer value from the integer value v
.
n
must be among 8, 16, 32, 64, and 128 and v
is encodable with n
-bits.
Examples:
int[8][42] = 42
empty(int[8][300])
int_float_convert
View sourceint_float_convert[x]
Conversion from int to float. Argument must be an int.
Example:
int_float_convert[3] = 3.0
int_float_convert[3.2] : error
int_spread_by_even
View sourceint_spread_by_even[R, value]
int_spread_by even(R, value, x..., spread)
Spread value
to the tuples in relation R
evenly as whole units.
Parameters
Parameter | Type | Description |
---|---|---|
R | Relation | Source relation. Must be grounded. |
value | Int | Integer to be divided among tuples as spread . Must be grounded. |
x... | Tuple | A tuple in R . |
spread | FloatBinary[#64] | Spread associated with x... . |
Explanation
int_spread_by_even
produces a relation with the tuples (x..., spread)
where the last element of each tuple (spread
)
is value
divided equally among the tuples in R
.
For example, if value
is 50
and R
has five tuples, spread
will be 10
for each tuple.
In cases of uneven spread, as when value
is 51
and R
has five tuples, the remainder is distributed by units to as many tuples as possible according to their lexicographic order.
int_spread_by_even
is empty if value
is negative.
Examples
Spread 30
evenly over three tuples:
def R = {"apple"; "banana"; "strawberry"}
def output = int_spread_by_even[R, 30]
//output> apple, 10
// banana, 10
// strawberry, 10
Spread 32
over three tuples, remainder applied to first two tuples:
def R = {"Atlanta"; "Seattle"; "San Francisco"}
def output = int_spread_by_even[R, 32]
//output> Atlanta, 11
// San Francisco, 11
// Seattle, 10
Spread 45
over three tuples using full expression:
def R = {"Miles Davis"; "Jimmy Smith"; "Ornette Coleman"}
def output(x...) = int_spread_by_even(R, 45, x...)
//output> Jimmy Smith, 15
// Miles Davis, 15
// Ornette Coleman, 15
See Also
int_spread_by_ratio
View sourceint_spread_by_ratio[R, value]
int_spread_by_ratio(R, value, x..., w, spread)
Spread value
to the tuples in relation R
as whole units proportionally to their
weight, which is the last element in each tuple.
Parameters
Parameter | Type | Description |
---|---|---|
R | Relation | Source relation. Must be grounded. |
value | SignedInteger[#64] | Integer to be divided among tuples as spread . Must be grounded. |
x... | Tuple | A tuple in R . |
spread | FloatBinary[#64] | Spread associated with x... . |
Explanation
int_spread_by_ratio
takes as input a relation R(x..., w)
, where x...
are one or more elements that serve as the key
and w
is a weight of type FloatBinary[#64]
or SignedInteger[#64]
.
int_spread_by_ratio
produces a relation with the tuples (x..., w, spread)
where the last element of each tuple (spread
)
is a spread among tuples, determined proportionally to a tuple’s weight as whole units.
For example, if the relation is {("X", 90); ("Y", 10)}
, "X"
will get 90%
of value
and "Y"
will get 10%
.
In cases where this split results in a decimal, int_spread_by_ratio
first distributes the floor value of the decimal number computed.
The remainder is distributed as single units in order starting from the
element with the highest decimal value.
int_spread_by_ratio
is empty if value
is negative.
Examples
Spread 100
over three tuples:
def R = {("Atlanta", 50);
("Seattle", 10);
("San Francisco", 40)}
def output = int_spread_by_ratio[R, 100]
//output> Atlanta, 50
// San Francisco, 40
// Seattle, 10
Spread 102
over three tuples with remainder:
def R = {("Atlanta", 50);
("Seattle", 10);
("San Francisco", 40)}
def output = int_spread_by_ratio[R, 102]
//output> Atlanta, 51
// San Francisco, 41
// Seattle, 10
Spread 1000
over three tuples using full expression:
def R = {("apple", 17);
("banana", 18);
("strawberry", 15)}
def output(x...) = int_spread_by_ratio(R, 1000, x...)
//output> apple, 340
// banana, 360
// strawberry, 300
See Also
Integer
View sourceInteger(x)
Holds if x
is an integer (fixed size or arbitrary precision).
Parameters
Parameter | Type | Description |
---|---|---|
x | Integer | An integer value. |
Explanation
An Integer
can be created with int
, uint
, or bigint
, or with an int or uint literal, as shown in the examples below.
Examples
def R = bigint[50]; int[64, 200]; uint[8, 4]
ic int_type_check(x in R) {
Integer(x)
}
def R = rational[16, -5, -7]; 5; 0x05
def output(x) = R(x) and Integer(x)
//output> 5; 0x05
See Also
FixedSizeInteger
, BigInteger
, SignedInteger
, and UnsignedInteger
is_Day
View sourceis_Day(x)
DEPRECATED
This function is deprecated and should be avoided. It will be removed soon.
Please use rel:base:Day(x)
instead.
Note that you have to include the rel:base
, because Day
is the deprecated constructor.
Holds if x
is a Day
period.
is_Hour
View sourceis_Hour(x)
DEPRECATED
This function is deprecated and should be avoided. It will be removed soon.
Please use rel:base:Hour(x)
instead.
Note that you have to include the rel:base
, because Hour
is the deprecated constructor.
Holds if x
is a Hour
period.
is_Microsecond
View sourceis_Microsecond(x)
DEPRECATED
This function is deprecated and should be avoided. It will be removed soon.
Please use rel:base:Microsecond(x)
instead.
Note that you have to include the rel:base
, because Microsecond
is the deprecated constructor.
Holds if x
is a Microsecond
period.
is_Millisecond
View sourceis_Millisecond(x)
DEPRECATED
This function is deprecated and should be avoided. It will be removed soon.
Please use rel:base:Millisecond(x)
instead.
Note that you have to include the rel:base
, because Millisecond
is the deprecated constructor.
Holds if x
is a Millisecond
period.
is_Minute
View sourceis_Minute(x)
DEPRECATED
This function is deprecated and should be avoided. It will be removed soon.
Please use rel:base:Minute(x)
instead.
Note that you have to include the rel:base
, because Minute
is the deprecated constructor.
Holds if x
is a Minute
period.
is_Month
View sourceis_Month(x)
DEPRECATED
This function is deprecated and should be avoided. It will be removed soon.
Please use rel:base:Month(x)
instead.
Note that you have to include the rel:base
, because Month
is the deprecated constructor.
Holds if x
is a Month
period.
is_Nanosecond
View sourceis_Nanosecond(x)
DEPRECATED
This function is deprecated and should be avoided. It will be removed soon.
Please use rel:base:Nanosecond(x)
instead.
Note that you have to include the rel:base
, because Nanosecond
is the deprecated constructor.
Holds if x
is a Nanosecond
period.
is_Second
View sourceis_Second(x)
DEPRECATED
This function is deprecated and should be avoided. It will be removed soon.
Please use rel:base:Second(x)
instead.
Note that you have to include the rel:base
, because Second
is the deprecated constructor.
Holds if x
is a Second
period.
is_Week
View sourceis_Week(x)
DEPRECATED
This function is deprecated and should be avoided. It will be removed soon.
Please use rel:base:Week(x)
instead.
Note that you have to include the rel:base
, because Week
is the deprecated constructor.
Holds if x
is a Week
period.
is_Year
View sourceis_Year(x)
DEPRECATED
This function is deprecated and should be avoided. It will be removed soon.
Please use rel:base:Year(x)
instead.
Note that you have to include the rel:base
, because Year
is the deprecated constructor.
Holds if x
is a Year
period.
json_string
View sourcejson_string[json_relation]
The string representation of a relation that encodes JSON data.
Example:
def json_relation[:name] = "Amira"
def json_relation[:age] = 32
def json_relation[:height] = missing
def 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"
]
}
last
View sourcelast[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)]
//output> 3
// 6
def output = last[1; 2; 3]
//output> 1
// 2
// 3
def output = last[(1, 2); (3, "abc")]
//output> 2
// "abc"
def output = last[(1, 2, 3); (4, 5)]
//output> 3
// 5
left_override
View sourceleft_override[R, S]
R <++ S
The (left) override operator is usually applied to relations of tuples (k..., v)
with a functional
dependency from the initial (key) arguments (k...)
to the last (value) argument v
.
R <++ S
contains all the tuples of R
, plus all the tuples in S
whose key is not in R
. Often, S
specifies default values for keys that are missing in R
.
In the result, a value in R
overrides a value in S
.
There are two equivalent ways to think about R <++ S
:
(1) S
is providing default values for keys that are missing in R
.
(2) The entries in R
are overriding the entries in S
.
Example | Value |
---|---|
2 <++ 3 | 2 |
1.5 <++ 3 | 1.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.
default_value[D, F, c]
. right_override
levenshtein
View sourcelevenshtein[string1, string2]
Calculate the Levenshtein distance between two strings.
Example:
levenshtein["kitten", "sitting"]
3
like_match
View sourcelike_match(like_string, string)
Match string with a SQL “LIKE” pattern; case-sensitive.
The %
character is a wildcard, and is not escapable.
Example:
like_match("\%PROMO\%", "this is a PROMOtion")
//output> () // true
like_match(raw"%PROMO%", "this is a PROMOtion")
//output> () // true
lined_csv
View sourcelined_csv[R]
Given an already loaded CSV relation R
, lined_csv[R]
is 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]
load_binary
View sourceload_binary[URI_string]
load_binary[R]
This is the main in-language API for loading files as binary string.
To load a file, either provide the string URI where the data resides,
or a configuration relation R
that describes the data load.
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:
:path
: The path to the file, e.g."azure://<account_name>.blob.core.windows.net/container/image.jpeg"
.
Optional:
:integration
: A relation containing storage integration configuration.
Example:
def config[:path] = "azure://<account_name>.blob.core.windows.net/container/file.bin"
def config[:integration, :provider] = "azure"
def config[:integration, :credentials, :azure_sas_token] = "<azure_sas_token>"
def output = load_binary[config]
load_csv
View sourceload_csv[URI_string]
load_csv[R]
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 binary relation indicating the file schema. The pairs are of the form(RelName, String)
. The column name is specified as a Symbol (of typeRelName
) and the data type asString
. For example, the pair(:a, "int")
indicates that column:a
has type"int"
. The following data types are supported:Name Type "boolean"
Boolean
"bool"
Boolean
"char"
Char
"date"
Date
"datetime"
DateTime
"decimal(n, digits)"
FixedDecimal
"float"
Float
"int(128)"
Int128
"int(64)"
Int64
"int"
Int
"sha-1"
SHA1
"string"
String
"uuid"
UUID
:syntax
: A relation containing syntax configuration. The following options can be specified::header
: A relation with(Int, RelName)
pairs, specifying the column names in the file, where theInt
indices indicate the column order, and the column name is provided as a Symbol (of typeRelName
). This option overrides the default (or existing) header names.:header_row
: AnInt
that specifies the row where the file header is. The column names are specified by the content of that row, if they are not defined using the header option above. The values -1 and 0 indicate that no header is present and the system creates column names for you.:datarow
: AnInt
that specifies the row from where to start parsing values into relations.:missingstrings
: One or multipleString
values that should be interpreted as missing values. By default, only empty fields are considered missing.:delim
: An ASCIIChar
that delimits individual fields while parsing. Defaults to','
.:quotechar
: An ASCIIChar
that signals a “quoted” field while parsing. Defaults to'"'
.:escapechar
: An ASCIIChar
used to “escape” one or multiplequotechar
and otherescapechar
values within a quoted (e.g., text) field. Defaults to'\\'
.:decimalchar
: An ASCIIChar
to be used when parsing float values that separates a decimal value. Defaults to'.'
.:groupmark
: An ASCIIChar
denoting the number grouping mark, this allows parsing of numbers that have e.g., thousand separators (like1,000.00
). By default, no group marks are permitted in numbers. If:groupmark
and:delim
are the sameChar
, then group marks are only permitted in “quoted” numbers. For instance, if both:groupmark
and:delim
are','
, then the quotes around"1,000"
are necessary to be processed correctly.
: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:
Loading from literal string value:
def config[:data] = """
A,B,C
1,2,3
"""
def my_data = load_csv[config]
Loading a CSV file using a constant path:
def y = load_csv["azure://<account_name>.blob.core.windows.net/container/data.csv"]
def x = y[:A, _]
In the example above, all values for column :A
(“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 config
:
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).
See Also
export_csv
, Char
, int
, RelName
, String
, Date
, DateTime
, decimal
, FixedDecimal
, and Boolean
.
load_csv_row_wise
View sourceload_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 backward compatibility, we now recommend using load_csv
instead, which puts the column name first.
load_iceberg
View sourceload_iceberg[URI_string]
load_iceberg[R]
Load one or multiple Apache Iceberg tables from cloud storage.
Parameters
Parameter | Type | Description |
---|---|---|
URI_string | String | String URI where the data resides. |
R | Relation | Configuration relation that describes the data load. Must be grounded. |
Explanation
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:
:path
: The location of the iceberg table, e.g."s3://bucket-name/path/to/table_iceberg"
.
Optional:
:integration
: A relation containing storage integration configuration.
The result is a set of relations, one per each column in the loaded Iceberg table, with header
<[optional_prefix], column_name, row_number, value>
.
Nested types (LIST, STRUCT and ARRAY) and embedded types (JSON, BSON) are not supported.
Examples
Here’s how to load a table from a private repository in S3:
def config[:path] = "s3://bucket-name/path/to/table_iceberg"
def config[:integration, :provider] = "s3"
def config[:integration, :credentials, :access_key_id] = "<access_key_id>"
def config[:integration, :credentials, :secret_access_key] = "<secret_access_key>"
def output = load_iceberg[config]
See Also
load_parquet
, load_csv
, and load_json
.
load_json
View sourceload_json[filename_or_url]
load_json[R]
The relation R
, which currently needs to either be an EDB or an
IDB but not a 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:
Loading literal JSON values:
def data = """{"name": "Anton", "age": 56}"""
def config[:data] = data
def json = load_json[config]
Loading a JSON file using a constant path:
def y = load_json["test.json"]
Loading a JSON file using a configuration relation:
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]
load_json_general
View sourceload_json_general[filename_or_url]
load_json_general[R]
Load a JSON file using the JSON General representation. This representation does not use the
data in the JSON document to make any schema (unlike load_json
). This means that arbitrary
JSON files can be loaded without scaling issues, even if the file has millions of distinct
property names.
The result consists of the following relations:
(:root, Entity)
: for the root of the JSON document(:child, Entity, Entity, Entity)
: for JSON objects and arrays, where the 1st argument is the parent, the 2nd argument is the name (for object) or index (for array) (the actual string name or index is in:value
), and the 3rd is the child node.(:name, Entity)
: for named JSON entities.(:value, Entity, <value>)
: for leaf values, like strings, integers etc, where<value>
is one the JSON data types (String
,Int64
,Float64
,Bool
,Missing
).(:array, Entity)
: for JSON arrays (necessary to distinguish empty object vs array)(:object, Entity)
: for JSON objects
Identical sub-trees in the document use the same entity, so the result is a directed-acyclic graph (DAG). It is important to consider the shared sub-trees when analyzing the JSON document.
Examples:
A single value:
def config:data = """
"abc"
"""
def json = load_json_general[config]
with json use value, child, root
ic { root.value ≡ "abc" }
A JSON array:
def config:data = """
[ "abc", "def", "ghi" ]
"""
def json = load_json_general[config]
with json use value, child, root
def index[v, x] = value(x, v) and Int(v)
ic { count[root.child] ≡ 3 }
ic { root.child[_].value ≡ ("abc"; "def"; "ghi") }
ic { root.child[index[1]].value ≡ "abc" }
ic { root.child[index[2]].value ≡ "def" }
ic { root.child[index[3]].value ≡ "ghi" }
A JSON object:
def config:data = """
{ "a": 1, "b": 2, "c": 3 }
"""
def json = load_json_general[config]
with json use value, child, root
def name[s, x] = value(x, s) and String(s)
ic { count[root.child] ≡ 3 }
ic { root.child[name["a"]].value ≡ 1}
ic { root.child[name["b"]].value ≡ 2}
ic { root.child[name["c"]].value ≡ 3}
load_jsonlines
View sourceload_jsonlines[filename_or_url]
load_jsonlines[R]
Parse and load a JSONLines file. JSONLines is a file format that considers each line of the text file as a separate JSON object.
Example:
def data = """{"name": "Anton", "age":56}\n{"name": "Alex", "age":44}"""
def config[:data] = data
def output = load_jsonlines[config]
ic {equal(output[1,:name], "Anton")}
ic {equal(output[1,:age], 56)}
ic {equal(output[2,:name], "Alex")}
ic {equal(output[2,:age], 44)}
load_jsonlines_general
View sourceload_jsonlines_general[filename_or_url]
load_jsonlines_general[R]
Load a JSON Lines file using the JSON General representation. See load_json_general
for a
description of the JSON General representation.
The JSON Lines file is represented identical to a JSON array. The root
node is an array,
and every line is a child of this array.
As opposed to load_jsonlines
, the line number is not the first argument in the result.
This makes it possible to share common sub-trees and values across documents.
load_parquet
View sourceload_parquet[URI_string]
load_parquet[R]
Load one or multiple Parquet files from cloud storage.
Parameters
Parameter | Type | Description |
---|---|---|
URI_string | String | String URI where the data resides. |
R | Relation | Configuration relation that describes the data load. Must be grounded. |
Explanation
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:
:path
: The path to the file, e.g."s3://bucket-name/path/to/file.parquet"
.
Optional:
:integration
: A relation containing storage integration configuration.
The result is a set of relations, one per each column in the loaded Parquet, with header
<[optional_prefix], column_name, row_number, value>
.
Nested types (LIST, STRUCT and ARRAY) and embedded types (JSON, BSON) are not supported.
Examples
Here’s how to load a file from a private repository in S3:
def config[:path] = "s3://bucket-name/path/to/file.parquet"
def config[:integration, :provider] = "s3"
def config[:integration, :credentials, :access_key_id] = "<access_key_id>"
def config[:integration, :credentials, :secret_access_key] = "<secret_access_key>"
def output = load_parquet[config]
See Also
load_iceberg
, load_csv
, and load_json
.
log
View sourcelog[x, y]
Logarithm of y with given base x.
Defined for non-negative x
and y
.
Example:
log[2, 8] = 3.0
log_card_est
View sourcelog_card_est[R]
The log base 2 of the cardinality estimate of a given relational abstraction R
.
lowercase
View sourcelowercase[string_or_char]
A string where all the characters are converted to lowercase. If a character is already lowercase or has no lowercase version, it remains unchanged.
Example:
def output = lowercase["aB1c"]
//output> "ab1c"
def output = lowercase['Â']
//output> 'â'
lowercase
does not take a locale option and does not handle local-specific case mapping
rules.
max
View sourcemax[R]
max(R, m)
The maximum value (m
) of the last element of all tuples in a relation R
.
Parameters
Parameter | Type | Description |
---|---|---|
R | Relation | Source relation. Must be grounded. |
m | Number | The maximum of the last element of the tuples in R . |
Explanation
max
aggregates over all tuples in R
.
Tuples in R
can have different lengths, and the length may vary from tuple to tuple.
Tuples with a non-numeric last element are ignored.
For example, if R
contains key-value pairs, max[R]
finds the maximum value for R
.
Note that max
groups the tuples by the data type of the final numeric element.
Typically, max
is used when the last elements of each tuple have the same type.
max
can be used with strings.
In this case, max
is determined according to lexicographical order.
For details on lexicographical ordering — particularly across data types — see enumerate
.
If R
is empty, max[R]
is false
(empty).
Use <++
(left override) if you need a specific value for the case where R
is empty.
Examples
Find the maximum value of a relation’s last element:
def output = max[{(2, 3); (1, 6)}]
//output> 6
Find the maximum value for each data type:
def R = {("a", rational[64, 2, 5]); ("b", rational[64, 1, 7]); ("c", 4.5); ("d", 6.7)}
def output = max[R]
//output> 2/5
// 6.7
Find the maximum value of a relation’s last element using full expression:
def R = {("a", rational[64, 2, 5]); ("b", rational[64, 1, 7]); ("c", rational[64, 3, 5])}
def output(x) = max(R, x)
//output> 3/5
Find the maximum value for relation with tuples of various lengths (the last element in each tuple is used to find the maximum value).
def R = { (10); (2, 30); (3, 50, 2)
}
def output = max[R]
//output> 30
See Also
max_k
View sourcemax_k[k, R]
max_k(k, R, mk)
The k
largest values in the set of all last elements
of tuples in a relation R
, excluding duplicates.
Parameters
Parameter | Type | Description |
---|---|---|
k | SignedInteger[#64] | Number of distinct largest values to be calculated for R . |
R | Relation | Source relation. Must be grounded. |
mk | Number | The maximum k of the last element of the tuples in R . |
Explanation
max_k
identifies the k
largest values in the last element of any tuple in R, excluding duplicates.
For example, if the last column contains 1, 2, 2, 3
and k = 2
, then max_k[2, R] = {2; 3}
.
max_k
aggregates over all tuples in R
.
Tuples in R
can have different lengths, and the length may vary from tuple to tuple.
Tuples with a non-numeric last element are ignored.
Note that max_k
groups the tuples by the data type of the last element.
This may cause unexpected results when used in relations with values of mixed types.
Typically, max_k
is used when the last elements of each tuple have the same type.
If R
contains fewer then k
distinct values, then max_k
will have fewer than k
elements as well.
The maximum supported value for k
is 10000
.
If R
is empty, max_k[K, R]
is false
(empty).
Use <++
(left override) if you need a specific value for the case where R
is empty.
Examples
Determine the two largest distinct values for a relation:
def R = {(2, 3); (1, 6); (3, 5); (1, 1); (4, 1); (2, 6)}
def output = max_k[2, R]
//output> 5, 6
Find the two largest distinct values in a relation using the full expression:
def R = {("A", 7.5); ("B", 8.6); ("C", 9.7); ("D", 7.5)}
def output(mk) = max_k(2, R, mk)
//output> 8.6
// 9.7
See Also
min_k
, argmin
, maximum
, min
, argmax
, sum
, product
, and average
.
maximum
View sourcemaximum[x, y]
Maximum of two arguments. The arguments should have the same type.
Examples:
maximum[3, 4] = 4
maximum[3.0, 4.0] = 4.0
See Also
mean
View sourcemean[R]
mean(R, m)
The arithmetic mean (m
) of the last elements of each tuple in the relation R
.
Parameters
Parameter | Type | Description |
---|---|---|
R | Relation | Source relation. Must be grounded. |
m | Number | The arithmetic mean of R . |
Explanation
mean
aggregates over all tuples in R
.
Tuples in R
can have different lengths, and the length may vary from tuple to tuple.
Note that mean
groups the tuples by the data type of the last element.
This may cause unexpected results when used in relations with values of mixed types.
Typically, mean
is used when the last elements of each tuple have the same numeric type.
If the relation R
contains tuples with a non-numeric last element, the result may not be accurate.
If R
is empty, mean[R]
is false
(empty).
Use <++
(left override) if you need a specific value for the case where R
is empty.
Examples
Calculate the arithmetic mean of the last elements of each tuple in a relation:
def output = mean[{(2, 3); (1, 6)}]
//output> 4.5
Calculate the arithmetic mean of the values in a relation using the full expression:
def R = {("a", rational[64, 2, 5]); ("b", rational[64, 1, 7]); ("c", rational[64, 3, 5])}
def output(m) = mean(R, m)
//output> 8/21
Calculate the arithmetic mean of the values in a relation with tuples of various lengths:
def R = {(10); (2, 30); (3, 50, 2)}
def output = mean[R]
//output> 14.0
Calculate the arithmetic mean of salary by department:
def salary = {("John", 126) ; ("Mary", 90); ("Paul", 117); ("Peter", 115); ("Tran", 145) }
def member = {("A", "John"); ("B", "Mary"); ("A", "Paul"); ("C" , "Peter"); ("C", "Tran") }
def department = {"A"; "B"; "C" }
def output = d in department: mean[salary[p] for p in member[d]]
//output> "A", 121.5
// "B", 90.0
// "C", 130.0
See Also
geometric_mean
, harmonic_mean
, weighted_mean
, mode
, max
, min
, sum
, and product
.
median
View sourcemedian[R]
median(R, m)
The median value of the last elements of each tuple in the relation R
.
Parameters
Parameter | Type | Description |
---|---|---|
R | Relation | Source relation. Must be grounded. |
m | Number | The median of R . |
Explanation
Computes the median, or “middle” value of the set of last elements of each tuple in R
.
If there are two “middle values”, then the mean of the two values is used.
For best results, tuples in R
should all have the same length,
and the last element of each tuple should be a Number
.
Note that, unlike other aggregations, median
does not group tuples by data type.
Examples
Determine median of a relation:
def R = {("A", 7); ("B", 8); ("C", 9.7); ("D", 7.5)}
def output = median[R]
//output> 8.35
Determine median of a relation using full expression:
def R = {("a", rational[64, 2, 5]); ("b", rational[64, 1, 7]); ("c", 4.5); ("d", 6.7); ("e", 1.2)}
def output(m) = median(R, m)
//output> 6.7
Determine median salary across departments:
def salary = {("John", 126) ; ("Mary", 90); ("Paul", 117); ("Peter", 115); ("Tran", 145) }
def member = {("A", "John"); ("B", "Mary"); ("A", "Paul"); ("C" , "Peter"); ("C", "Tran") }
def department = {"A"; "B"; "C" }
def output = d in department: median[salary[p] for p in member[d]]
//output> "A", 121.5
// "B", 90.0
// "C", 130.0
metaphone
View sourcemetaphone[string_value, length]
metaphone
returns an encoding of the phonetic representation of string_value
.
metaphone
lets you compare words and sentences based on how they sound in English. The
metaphone is considered as an improvement of the soundex
algorithm, and does a better job
at matching words and names which sound
similar.
string_value
could be any arbitrary long string.
length
is the length of the encoding that is used for comparison purpose. A length of 4
is commonly used.
Examples:
def output = metaphone["Smith", 4]
//output> sm0
def output = metaphone["Smythe", 4]
//output> sm0
def output = metaphone["Christina", 4]
//output> xrst
def output = metaphone["Cristine", 4]
//output> krst
def output = metaphone["I like Music", 4]
//output> ilkm
def output = metaphone["i loak Museek", 4]
//output> ilkm
def output = metaphone["RelationalAI", 4]
//output> rlxn
def output = metaphone["rellationalleAI", 4]
//output> rlxn
Here a simple illustration. Consider the following:
def my_favorite_bands = { "Metallica"; "Iron Maiden"; "Wolfheart"; "Insomium" }
def do_I_like = "Mee ta li ka"
def output = {y in my_favorite_bands : metaphone(do_I_like, 4, z), metaphone[y, 4] = z from z}
the script above returns "Metallica"
since since "Mee ta li ka"
and "Metallica"
have
the same metaphone code.
Microsecond
View sourceMicrosecond[n]
DEPRECATED
This function is deprecated and should be avoided. It will be removed soon.
Please use the Microsecond constructor, ^Microsecond
, instead.
Create a period of n
microseconds.
Millisecond
View sourceMillisecond[n]
DEPRECATED
This function is deprecated and should be avoided. It will be removed soon.
Please use the Millisecond constructor, ^Millisecond
, instead.
Create a period of n
milliseconds.
min
View sourcemin[R]
min(R, m)
The minimum value (m
) of the last element of all tuples in a relation R
.
Parameters
Parameter | Type | Description |
---|---|---|
R | Relation | Source relation. Must be grounded. |
m | Number | The minimum of the last element of the tuples in R . |
Explanation
min
aggregates over all tuples in R
.
Tuples in R
can have different lengths, and the length may vary from tuple to tuple.
Tuples with a non-numeric last element are ignored.
For example, if R
contains key-value pairs, min[R]
finds the minimum value for R
.
Note that min
groups the tuples by the data type of the final numeric element.
Typically, min
is used when the last elements of each tuple have the same type.
min
can be used with strings.
In this case, min
is determined according to lexicographical order.
For details on lexicographical ordering, see enumerate
.
If R
is empty, min[R]
is false
(empty).
Use <++
(left override) if you need a specific value for the case where R
is empty.
Examples
Find the minimum value of a relation’s last element:
def output = min[{(2, 3); (1, 6)}]
//output> 3
Find the minimum value for each data type:
def R = {("a", rational[64, 2, 5]); ("b", rational[64, 1, 7]); ("c", 4.5); ("d", 6.7) }
def output = min[R]
//output> 4.5
// 1/7
Find the minimum value of a relation’s last element using full expression:
def R = {("a", rational[64, 2, 5]); ("b", rational[64, 1, 7]); ("c", rational[64, 3, 5])
}
def output(x) = min(R, x)
//output> 1/7
Find the minimum value for a relation with tuples of various lengths (the last element in each tuple is used to find the minimum value):
def R = { (10); (2, 30); (3, 50, 2)}
def output = min[R]
//output> 2
See Also
min_k
View sourcemin_k[k, R]
min_k(k, R, m)
Find the k
smallest values in the set of all last elements
of tuples in a relation R
, excluding duplicates.
Parameters
Parameter | Type | Description |
---|---|---|
k | SignedInteger[#64] | The number of distinct minimum values to be calculated for R . |
R | Relation | Source relation. Must be grounded. |
mk | Number | The minimum k of the last element of the tuples in R . |
Explanation
min_k
identifies the k
smallest values in the last element of any tuple in R, excluding duplicates.
For example, if the last column contains 1, 2, 2, 3
and k = 2
, then min_k[2, R] = {1; 2}
.
min_k
aggregates over all tuples in R
.
Tuples in R
can have different lengths, and the length may vary from tuple to tuple.
Tuples with a non-numeric last element are ignored.
Note that min_k
groups the tuples by the data type of the last element.
This may cause unexpected results when used in relations with values of mixed types.
Typically, min_k
is used when the last elements of each tuple have the same type.
If R
contains fewer then k
distinct values, then min_k
will have fewer than k
elements as well.
The maximum supported value for K
is 10000
.
If R
is empty, min_k[k, R]
is false
(empty).
Use <++
(left override) if you need a specific value for the case where R
is empty.
Examples
Determine the two smallest distinct values for in relation:
def R = {(2, 3); (1, 6); (3, 5); (1, 1); (4, 1); (2, 6)}
def output = min_k[2, R]
//output> 1, 3
Determine the two smallest distinct values in a relation using the full expression:
def R = {("A", 7.5); ("B", 8.6); ("C", 9.7); ("D", 7.5)}
def output(mk) = min_k(2, R, mk)
//output> 7.5
// 8.6
See Also
max_k
, argmin
, minimum
, min
, argmax
, sum
, product
, and average
.
min_max_normalization
View sourcemin_max_normalization[R]
Min-Max normalization: .
Also known as min-max scaling or rescaling.
minimum
View sourceminimum[x, y]
Minimum of two arguments. The arguments should have the same type.
Examples:
minimum[3, 4] = 3
minimum[3.0, 4.0] = 3.0
Minute
View sourceMinute[n]
DEPRECATED
This function is deprecated and should be avoided. It will be removed soon.
Please use the Minute constructor, ^Minute
, instead.
Create a period of n
minutes.
missing
View sourcemissing
Singleton missing value.
Examples:
missing[] = missing
equal( (x : missing(x)) , {missing} )
Missing
View sourceMissing(x)
Tests whether x
has the data type Missing
.
The only data value that is of type Missing
is missing
.
Used for imported data that contain explicit nulls (such as JSON data).
Missing
(with a capital) refers to the data type, while missing
refers to the data.
Examples:
Query that returns all relations without missing
as the second argument:
def R = { (1, 2); (3, missing) }
def output(x, y) = R(x, y) and not Missing(y)
//output> (1, 2)
mode
View sourcemode[R]
mode(R, md)
Find the most common value in the last element of all tuples in a relation R
.
Parameters
Parameter | Type | Description |
---|---|---|
R | Any | Source relation. Must be grounded. |
md | Any | The mode of R . |
Explanation
If there are multiple mode values, then mode
chooses the first one according to lexicographical order.
For details on lexicographical ordering — particularly across data types — see enumerate
.
mode
aggregates over all tuples in R
whose last element is numeric.
Tuples in R
can have different lengths, and the length may vary from tuple to tuple.
Tuples with a non-numeric last element are ignored.
Note that mode
groups the tuples by the data type of the last element.
This may cause unexpected results when used in relations with values of mixed types.
Typically, mode
is used when the last elements of each tuple have the same type.
If R
is empty, mode[R]
is false
(empty).
Use <++
(left override) if you need a specific value for the case where R
is empty.
Examples
Find the most common value in a relation:
def R = {(5, 8); (8, 6); (13, 12); (9, 6); (2, 9); (7, 6)}
def output = mode[R]
//output> 6
Find most common value in relation using full expression:
```rel
def R = {("A", "A"); ("B", "A"); ("C", "C"); ("D", "A"); ("E", "B");}
def output(md) = mode(R, md)
//output> "A"
Find most common value in a relation with tuples of various lengths:
def R = {("A", 6, "A"); ("B", 7, "C"); ("C", "C"); ("D", "A"); ("E", "A")}
def output = mode[R]
//output> "A"
model_is_function (IC)
View sourceic model_is_function
An integrity constraint ensuring that rel:catalog:model
has a functional dependency
from the name to the actual value.
modulo
View sourcemodulo[x, y]
modulo(x, y, m)
Remainder after floored division.
Parameters
Parameter | Type | Description |
---|---|---|
x | Number | Dividend. Must be grounded. |
y | Number | Divisor. Must be grounded. |
m | Number | Remainder. |
Not all numeric values can be mixed with each other. The following combinations work:
x | y | m |
---|---|---|
Number | Same as x | Same as x |
SignedInteger , UnsignedInteger | SignedInteger , UnsignedInteger | Type of y . Bit size is the larger of the bit sizes of x and y . |
SignedInteger[#64] , FloatBinary[#64] | Number | Type of x . |
Number | SignedInteger[#64] , FloatBinary[#64] | Type of y . |
FloatBinary | SignedInteger[#64] | Type of x . |
SignedInteger[#64] | FloatBinary | Type of y . |
Rational | SignedInteger[#64] | Rational[n] where n is the greater of the number of bits in x and y . |
SignedInteger[#64] | Rational | Rational[n] where n is the greater of the number of bits in x and y . |
The remainder in the division algorithm for dividing x
by y
using floored division for the quotient.
That is, modulo[x, y]
is equivalent to x - (y * floor_divide[x, y])
.
The sign of the remainder is the same as the divisor y
.
If y
is positive, the range is from 0 to y, inclusive.
If y
is negative, range is from y to 0, inclusive.
modulo[x, y]
is defined when either the types of x
and y
are the same, or
either operand is of type SignedInteger[#64]
or FloatBinary[#64]
.
modulo[x, y]
is false
when y
= 0 for integer arguments.
Examples
Compute remainder for two integers:
def output = modulo[8, 3]
//output> 2
Compute remainder for two integers using full expression:
def output(m) = modulo(8, -3, m)
//output> -1
Compute remainder for rational and integer:
def output = modulo[rational[64, 8, 3], 2]
//output> 2/3
Confirm that modulo
is empty when y
= 0
:
def output = empty(modulo[3, 0])
//output> () // true
Month
View sourceMonth[n]
DEPRECATED
This function is deprecated and should be avoided. It will be removed soon.
Please use the Month constructor, ^Month
, instead.
Create a period of n
months.
multiply
View sourcemultiply[x, y]
multiply(x, y, p)
x * y
Multiplication of two numbers.
Parameters
Parameter | Type | Description |
---|---|---|
x | Number | First factor. Must be grounded. |
y | Number | Second factor. Must be grounded. |
p | Number | Product x * y . |
Not all numeric values can be mixed with each other. The following combinations work:
x | y | p |
---|---|---|
Number | Same as x | Same as x |
Rational , FixedDecimal | SignedInteger , UnsignedInteger | Same as x |
SignedInteger , UnsignedInteger | Rational , FixedDecimal | Same as y |
SignedInteger[#64] | SignedInteger[#128] | SignedInteger[#128] |
SignedInteger[#128] | SignedInteger[#64] | SignedInteger[#128] |
Number | FloatBinary[#64] | FloatBinary[#64] |
FloatBinary[#64] | Number | FloatBinary[#64] |
Explanation
In contrast to add
and subtract
, x
and y
need to be grounded and specified by the user.
Specifying only x
and p
or only y
and p
is not sufficient as the system can’t compute the inverse.
Examples
Multiply two integers using *
:
def output = 24 * 2
//output> 48
Multiply one float by another using multiply
:
def output = multiply[8.4, 2.1]
//output> 17.64
Multiply a rational by an integer using full expression:
def output(x) = multiply(rational[64, 8, 3], 2, x)
//output> 16/3
See Also
murmurhash3f
View sourcemurmurhash3f[v]
Hash v
according to the MurmurHash3f algorithm with the default seed 0
,
as a UInt128.
Equivalent to murmurhash3f_with_seed[0, v]
.
murmurhash3f_with_seed
View sourcemurmurhash3f_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:
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
seed
s; for such
seed
s, this implementation’s internals should provide byte-identical results.
But this implementation accepts seed
s up to and including 128-bit integer types.
(For UInt32
seed
s, the reference implementation initializes h1
/h2
,
the two UInt64
s in which it accumulates/mixes the digest, with copies of seed
.
This implementation does the same for UInt32
seed
s, and also for all other
seed
types that are less than or equal to 64 bits. For 128-bit seed
s, this implementation
initializes h1
with the seed
’s low bits and h2
with the seed
’s high bits.)
Examples
// Without a seed
murmurhash3f["cat"] = 0x37322aa78b4b4ef4816da65505e8efaa
// With a seed
murmurhash3f_with_seed[8675309, "cat"] = 0x9fd1d18093ba94b6f454b48e58011643
murmurhash3f_with_seed[8675309, :bunny] = 0x56f800aed5ff3b7300ace61c691e7568
// byte-identical values of different types hash differently
murmurhash3f[0x01] = 0x6ed3439777f613f7df39df0849d45e09
murmurhash3f[1] = 0x9116cd3f0a651c49f1674100935b29bf
Nanosecond
View sourceNanosecond[n]
DEPRECATED
This function is deprecated and should be avoided. It will be removed soon.
Please use the Nanosecond constructor, ^Nanosecond
, instead.
Create a period of n
nanoseconds.
nanoseconds_to_datetime
View sourcenanoseconds_to_datetime[ns]
Convert nanoseconds (from the unix epoch) to datetime.
Analogous to datetime.datetime.utcfromtimestamp(seconds) in python.
Example:
nanoseconds_to_datetime[24 * 60 * 60 * 10^9]
is 1970-01-02T00:00:00
(one day after unix_epoch
).
num_bytes
View sourcenum_bytes[str]
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"] = 4
num_bytes["中文例子"] = 12
num_chars
View sourcenum_chars[str]
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"] = 4
num_chars["中文例子"] = 4
Number
View sourceNumber(x)
Holds if x
is a number (for example, Int
,Float
, or their fixed-width versions).
See Also
Example:
Integrity constraint that tests whether x
is of type Number
(throws if x
is not of type Number
):
def R = {1; 1.5; uint[8,3]; 4; float[32, 1.321]}
ic number_ic { subset(R, Number) }
numerator
View sourcenumerator[x]
Numerator of a rational-like number.
Examples:
numerator[rational[64, 1, 3]] = 1
numerator[rational[64, 1, 100]] = 1
numerator[rational[64, 1, 100] + rational[64, 1, 3]] = 103
numerator[parse_decimal[#64, #2, "3.14"]] = 314
numerator[parse_decimal[#64, #5, "3.14159"]] = 314159
numerator[5] = 5
pack
View sourcepack(x₁, ..., xₙ, v)
Creates a packed structure v
storing the values (x₁, ..., xₙ)
in sequence.
pack
cannot be used with point-free syntax.
Direct usage of pack
should be avoided, as it serves primarily as a low-level
interface for value types.
parse_date
View sourceparse_date[d, format]
Parse Date.
This function is only defined for a valid combination of date string
d
and format string format
, and invalid arguments will evaluate
to false
(the empty relation, {}
).
Examples:
def output = parse_date["2018-06-12", "Y-m-d"]
//output> 2018-06-12
For details on the format parameter, see the Julia documentation for Dates.DateFormat
(opens in a new tab).
parse_datetime
View sourceparse_datetime[date_string, format]
parse_datetime(date_string, format, date)
Parses datetime information (date_string
) given a date-time format (format
).
Parameters
Parameter | Type | Description |
---|---|---|
date_string | String | A string with date and time information formatted according to format . Must be grounded. |
format | String | A valid date-time format. Must be grounded. |
date | DateTime | A DateTime object containing the parsed date and time information. |
Explanation
The form parse_datetime[date_string, format]
can be used to create the Datetime
value (date
).
The form parse_datetime(date_string, format, date)
can be used to check that date
maps to date_string
given the date-time format format
.
parse_datetime
evaluates to false
if date_string
or format
is invalid.
Parameters for DateTime Format Strings
Parameter | Example | Description |
---|---|---|
y | 2024 | Matches year. |
m | 1, 01 | Matches 1 or 2-digit months. |
d | 1, 01 | Matches 1 or 2-digit days. |
H | 00 | Matches hours (24-hour clock). |
I | 00 | For outputting hours with 12-hour clock. |
M | 00 | Matches minutes. |
S | 00 | Matches seconds. |
s | .500 | Matches milliseconds. |
e | Mon, Tues | Matches abbreviated days of the week. |
E | Monday | Matches full name days of the week. |
p | AM | Matches AM/PM (case-insensitive). |
yyyymmdd | 19960101 | Matches fixed-width year, month, and day. |
z | +04:00, +0400, UTC+4 | Matches a numeric UTC offset. |
Z | Asia/Dubai, UTC | Matches names of time zones from the TZ database. |
u | Jan | Matches abbreviated months according to the _locale_keyword. |
U | January | Matches full month names according to the _locale_keyword. |
Examples
Parse a string with date and time information:
def output = parse_datetime["2022-03-01 02:21:09", "y-m-d H:M:S"]
//output> 2022-03-01T02:21:09.000Z
Parse a string with date and time (incl. milliseconds) information:
def output(x) = parse_datetime("2024-01-15 00:00:00.003","y-m-d H:M:S.sss", x)
//output> 2024-01-15T00:00:00.003Z
Parse a string with timezone information:
def output = parse_datetime["2018-03-11 01:00 America/New_York", "Y-m-d H:M Z"]
//output> 2018-03-11T06:00:00.000Z
where the time-zone name must match the names in the time-zone (tz) database.
See Also
string
, parse_int
, parse_float
, and parse_date
.
parse_decimal
View sourceparse_decimal[bits, precision, string]
Parse a string representation of a fixed-point decimal number to a decimal[bits, precision]
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 precision
parameter, then the number is rounded to the nearest number.
This function is only defined for valid arguments. For invalid arguments it will be 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"]
{}
parse_float
View sourceparse_float[string]
Parse a string representation of a float to a FloatBinary[#64]
Note that this currently does not consider a locale (decimal separator is always .
)
Is false
(empty) if the string fails to parse as an integer.
Examples:
parse_float["3.14"] = 3.14
parse_float["3"] = 3.0
empty(parse_int["hello"])
parse_int
View sourceparse_int[string]
Parse a string representation of an integer to a SignedInteger[#64]
Is false
(empty) if the string fails to parse as an integer.
Example:
parse_int["123"] = 123
empty(parse_int["hello"])
parse_int128
View sourceparse_int128[string]
Parse a string representation of an integer to a SignedInteger[#128]
Is false
(empty) if the string fails to parse as an integer.
Example:
parse_int128["9223372036854775808"] = 9223372036854775808
empty(parse_int["hello"])
parse_json
View sourceparse_json[json_string_value]
Parses a JSON value directly from a string.
Example:
def json = parse_json["""{"name": "Anton", "age": 56}"""]
parse_json_general
View sourceparse_json_general[json_string_value]
Parse a JSON document directly from a string using the JSON General representation. See
load_json_general
for a description of the JSON General representation.
Example:
def json = parse_json_general["123"]
with json use value, child, root
ic { root.value ≡ 123 }
parse_jsonlines
View sourceparse_jsonlines[jsonlines_string_value]
Parse a JSON Lines file directly from a string.
The result of parse_jsonlines
is an Int64
line number followed by the Rel representation
of the JSON document as in load_json
.
Example:
def output = parse_jsonlines["""
{"name": "Luca", "age": 44}
{"name": "Kai", "age": 23}
{"name": "Harper", "age": 21}
"""]
ic { equal(count[output], 6) }
ic { equal(output[1, :name], "Luca") }
ic { equal(output[2, :name], "Kai") }
ic { equal(output[3, :name], "Harper") }
parse_jsonlines_general
View sourceparse_jsonlines_general[json_string_value]
Parse a JSON Lines file directly from a string using the JSON General representaiton. See
load_json_general
for a description of the JSON General representation.
The result of parse_jsonlines_general
has the same representation as
load_jsonlines_general
.
parse_uuid
View sourceparse_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
Pattern
View sourcePattern(x)
Holds if x
is of type Pattern
, which is a compiled regular expression (see regex_compile
).
Example:
Integrity constraint that tests whether x
is of type Pattern
:
def R = regex_compile["a.*b"]
ic pattern_ic(x in R) {
Pattern(x)
}
pattern_match
View sourcepattern_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")
//output> () // true
percentile
View sourcepercentile[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 (opens in a new tab). 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]
//output> 17.6
percentile_nearest
View sourcepercentile_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 (opens in a new tab)).
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]
//output> 16
period_add
View sourceperiod_add[period1, period2]
Add two periods. For now, they need to be of the same type.
def output = period_add[Minute[3], Minute[4]]
//output> 7
period_day_to_int
View sourceperiod_day_to_int[day]
Conversion from period Day
to int
.
In other words, returns the value of Day
data type as an integer.
Example:
def num_of_days = period_day_to_int[^Day[3]]
ic { equal(num_of_days, 3) }
period_max
View sourceperiod_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]
//output> () // true
period_min
View sourceperiod_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]
//output> () // true
pivot
View sourcepivot[T]
pivot(T, tuple_position, value)
Pivot a relation T
.
The pivoted relation has the form (tuple_position, value)
, where tuple_position
is the tuple position of each element within T
and value
is its corresponding value.
Parameters
Parameter | Type | Description |
---|---|---|
T | Relation | Source relation. Must be grounded. |
tuple_position | Int | The position of the element value within T . |
value | Any | An individual element within T . |
Explanation
If a relation is seen as a table, then pivot
rotates the table, such that columns in the relations become rows.
Each row in the rotated relation is prefixed with its column position.
The relation pivot
in Rel performs a transformation that is known in other systems often as unpivot or melt.
More precisely, pivot
maps a relation T
to a binary relation that contains all elements in T
which are keyed by their tuple position(s) in T
.
That is, pivot[(t1, ..., tn)]
maps to the relations {(1, t1);... (n, tn)}
.
If a relation has three elements, for example, pivot
keys first elements with 1
, second elements with 2
,and third elements with 3
.
pivot
will work for relations with many tuples, even if the tuples do not have the same arity.
That is, the table need not be “rectangular” for pivot
to work.
pivot[true]
and pivot[false]
are both false
(the empty relation).
Examples
Pivot an arity-4 relation using shorthand:
def output = pivot[(5, 60, 7, 2.0)]
//output> (1, 5)
// (2, 60)
// (3, 7)
// (4, 2.0)
Pivot mixed-arity relation using full expression:
def employees = {
("jane", 42, "engineering");
("tran", 24)
}
def output = x... : pivot(employees, x...)
//output> 1, jane
// 1, tran
// 2, 24
// 2, 42
// 3, engineering
If relation R
is unary, pivot[R]
will turn it into a binary relation where the first element of each tuple is 1
.
def output = pivot[{5; 6}]
//output> 1, 5
// 1, 6
pop_standard_deviation
View sourcepop_standard_deviation[R]
pop_stddev[R]
Population standard deviation
pop_zscore_normalization
View sourcepop_zscore_normalization[R]
Z-score normalization (population) of (the last argument of) the relation R
.
power
View sourcepower[b, n]
power(b, n, e)
b ^ n
Exponentiation of b
to the power of n
.
Parameters
Parameter | Type | Description |
---|---|---|
b | Number | Base. Must be grounded. |
n | Number | Exponent. Must be grounded. |
e | Number | Exponentiation b ^ n . |
Not all numeric values can be mixed with each other. The following combinations are valid:
b | n | e |
---|---|---|
Number | SignedInteger[#64] | Same as b |
SignedInteger[#64] , FloatBinary[#64] | FloatBinary[#64] | FloatBinary[#64] |
BigInteger | BigInteger | BigInteger |
When both b
and n
are integer types, n
cannot be negative.
When b
is negative, n
must have an integer value like 2
, -3
, or 4.0
.
The data type of n
doesn’t need to be integer. Floating point numbers are also allowed as long as their value represents an integer number.
Examples
Using only positive integers ensures the result is an integer too:
def output = 2 ^ 8, power[5, 2]
// output> 256, 25
One can also mix integer and floating-point numbers:
def output = power(3.0, 2, 9.0)
//output> () // true
However, the exponent needs to have an integer value when the base is negative:
def output = (-10)^-4.0
// output> 0.0001
prefix_join
View sourceprefix_join[R, S]
R <: S
The prefix join (or restriction) of S
to R
consists of the tuples (x..., y...)
in S
where the prefix (x...)
is in R
.
That is, R <: S
contains the tuples in S
that have a prefix in R
.
Example | Normalized |
---|---|
n <: edge | x, y: edge(x, y) and x = n |
female <: parent | x, y: female(x) and parent(x, y) |
t <: players | x, p: players(x, p) and t = x |
t.players <: age | p, v: players(t, p) and age(p, v) |
intern <: salary | p, v: intern(p) and salary(p, v) |
The restriction operator can also be used to select subsets of JSON-like relations:
-
:a <: json
wherejson
is{"a": {"b": 1, "c": 2}, "d": 3}
has value{"a": {"b": 1, "c": 2}}
-
(:[], _, :a) <: json
wherejson
is[ {"a": 1, "b": 2}, {"a": 3, "b": 4} ]
has value[ {"a": 1}, {"a": 3} ]
.
product
View sourceproduct[R]
product(R, p)
The product (p
) of the last element of all tuples in a relation R
.
Parameters
Parameter | Type | Description |
---|---|---|
R | Relation | A relation whose tuples contain numeric data types. Must be grounded. |
p | Number | The product of the last element of the tuples in R . |
Explanation
product
aggregates over all tuples in R
whose last element is numeric.
Tuples in R
can have different lengths, and the length may vary from tuple to tuple.
Tuples with a non-numeric last element are ignored.
For example, if R
contains key-value pairs, product[R]
finds the product of values for R
.
Note that product
groups the tuples by the data type of the final numeric element.
Typically, product
is used when the last elements of each tuple have the same type.
If R
is empty, product[R]
is false
(empty).
Use <++
(left override) if you need a specific value for the case where R
is empty.
Examples
Find the product of a relation’s last element:
def output = product[{(1, 4); (2, 5)}]
//output> 20
Calculate the product for each data type:
def R = {("a", rational[64, 2, 5]); ("b", rational[64, 1, 7]); ("c", 4.5); ("d", 6.7)}
def output = product[R]
//output> 30.150000000000002
// 2/35
Calculate the product of a relation’s last element using full expression:
def R = {("A", 7.5); ("B", 8.6); ("C", 9.7); ("D", 7.5)}
def output(p) = product(R, p)
//output> 4692.375
Calculate the product of relations whose last elements are rationals:
def R = {("A", rational[64, 8, 3]); ("B", rational[64, 9, 7]); ("C", rational[64, 11, 4]); ("D", rational[64, 8, 3])}
def output = product[R]
//output> 176/7
See Also
proper_subset
View sourceproper_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
.
rad2deg
View sourcerad2deg[r]
rad2deg(r, d)
Convert radians to degrees.
Parameters
Parameter | Type | Description |
---|---|---|
r | Float , Int | d in radians. Must be grounded. |
d | Float | r in degrees. |
Examples
Convert -π/2 to degrees:
def output = rad2deg[-pi_float64/2]
//output> -90.0
Convert π to degrees using full expression:
def output(d) = rad2deg(pi_float64, d)
//output> 180.0
random_mersenne_twister
View sourcerandom_mersenne_twister[seed, R]
Generates a pseudorandom number for every tuple in R
using the Mersenne Twister PRNG.
random_mersenne_twister
takes a relation R(xs...)
and produces a relation with the
tuples (xs..., r)
where r
is a pseudorandom number generated by using the Mersenne
Twister algorithm with the given seed
. The value r
is a Float64 in the range of [0, 1].
The seed is required to be a number convertible to an unsigned 128-bit integer (UInt128
)
or a DateTime
. For a seed dt
of type DateTime
the value of epoch_milliseconds[dt]
is
used as seed.
Please note that if seed
has more than one value, then the smallest value in seed
will
be used as the seed (according to the native sort order that is used by sort
). If seed
is empty, then the result is empty.
Example:
def output = random_mersenne_twister[0, true]
//output> (0.8236475079774124,)
def output = random_mersenne_twister[random_uint128, 'a']
//output> ('a', 0.590845)
def sample = {'a'; 'b'; 'c'}
def output = random_mersenne_twister[random_uint128, sample]
//output> ('a', 0.590845)
// ('b', 0.766797)
// ('c', 0.566237)
def output = random_mersenne_twister[datetime_now, true]
//output> (0.09946255273771532,)
random_threefry_float64
View sourcerandom_threefry_float64[key1, key2]
Generates a pseudorandom number of type Float64
between 0.0 and 1.0 using the Threefry algorithm.
The Threefry algorithm depends on two keys: key1
and key2
of type UInt64
or Int64
.
One key can be used as the seed. The other key can be used as the stream position.
Which key is used for what is up to the user.
Examples:
Getting a single random Float64
number:
def output = random_threefry_float64[1234, 1]
//output> 0.14708645730224323
Generating a sequence of random Float64
numbers using a user-specific seed:
def output = random_threefry_float64[1234, i] for i in range[1, 3, 1]
//output> (1, 0.14708645730224323)
// (2, 0.18124311325337028)
// (3, 0.14463837673485513)
Using a randomly generated (but deterministic) seed via random_threefry_uint64
:
def seed = random_threefry_uint64[1234, 0]
def output = random_threefry_float64[seed, i] for i in range[1, 3, 1]
//output> (1, 0.2959011588531637)
// (2, 0.5971368640131505)
// (3, 0.4259318598026802)
Generating a random Float64
number from the indeterministic random seed random_uint64
:
def output = random_threefry_float64[random_uint64, 0]
random_threefry_uint64
View sourcerandom_threefry_uint64[key1, key2]
Generates a pseudorandom number of type UInt64
using the Threefry algorithm.
The Threefry algorithm depends on two keys: key1
and key2
of type UInt64
or Int64
.
One key can be used as the seed. The other key can be used as the stream position.
Which key is used for what is up to the user.
Note that the output of random_threefry_uint64
can be used as a key again in a subsequent call.
This capability allows the user to start a new random sequence from a previous sequence without
the need to track which keys have already been used.
Examples:
Getting a single random UInt64
number:
def output = random_threefry_uint64[1234, 1]
//output> 0xbf025a77543cc31d
Generating a sequence of random UInt64
numbers:
def output = random_threefry_uint64[1234, i] for i in range[1, 3, 1]
//output> (1, 0xbf025a77543cc31d)
// (2, 0xe532e65f2dc0c673)
// (3, 0x1bb25070549d29e7)
Generating two sequences of random UInt64
numbers by creating a new seed from the previous seed:
def seed1 = random_threefry_uint64[1234, 0]
def seed2 = random_threefry_uint64[seed1, 0]
def output:one = random_threefry_uint64[seed1, i] for i in range[1, 3, 1]
def output:two = random_threefry_uint64[seed2, i] for i in range[1, 3, 1]
//output> (:one, 1, 0x2ca4bc02da81f726)
// (:one, 2, 0x12898ddf6262c27b)
// (:one, 3, 0xd606d09ded02d4dd)
// (:two, 1, 0x48879dd755a393be)
// (:two, 2, 0xc5683a27c1e876a7)
// (:two, 3, 0xfdb025894557c350)
random_uint128
View sourcerandom_uint128
Random number generated using the random device. It is an unsigned 128-bit integer.
A single random number is generated using the random device of the operating system for every transaction. Within the transaction, the random number does not change. The random number can be used as the seed of a pseudo-random number generator.
Examples:
def output = random_uint128
//output> (0x648fa1de9056c1c7de7fc61bc138f5a8,)
Please note that random numbers need to be used with caution in views that need to be materialized or even incrementally maintained. If a view depends on a random number, then it needs to be recomputed every time the view is needed because the random number changes with every transaction and the view is always be consistent with its inputs.
If a random seed should not change with every transaction, then the state of a seed should be managed explicitly as an EDB. For example, a seed uses for a PRNG can be initialized in one transaction and then the same value is used from that point. In this way, materialized views involving random numbers can be reused.
random_uint64
View sourcerandom_uint64
Random number generated using the random device. It is an unsigned 64-bit integer.
This is a truncation of random_uint128
to the lower 64 bits. It does not provide an
additional source of random numbers.
Please check out the documentation for random_uint128
to get more information about how to
use random numbers in various situations.
Example:
def output = random_uint64
//output> (0xde7fc61bc138f5a8,)
range
View sourcerange[start, stop, step]
range(start, stop, step, x)
Generate a relation with integer values between start
and stop
, inclusive, advancing by step
each time.
Parameters
Parameter | Type | Description |
---|---|---|
start | Int[b] , UInt[b] , Float | Starting point for range (inclusive). Must be grounded. |
stop | same as start | Ending point for range (inclusive). Must be grounded. |
step | same as start | Step size. Positive integer. Must be grounded. |
x | same as start | Result of range . |
b
can be 8
, 16
, 32
, 64
, or 128
.
Explanation
range
produces a one-column relation containg the values start
, start + step
, start + 2*step
and so on as long as the values don’t exceed the value defined by stop
.
That is, if start <= stop
and step > 0
, then range[start, stop, step]
has all the values
x = start + i * step <= stop
for non-negative integers i
.
Can be used to generate a sequence of numbers.
step
must be a positive integer.
If start > stop
or step <= 0
, then range[start, stop, step]
is empty.
Examples
Generate a sequence of numbers from 2 to 10, incrementing by 2:
def output(x) = range(2, 10, 2, x)
//output> 2
// 4
// 6
// 8
// 10
Generate a sequence of numbers from 0 to 6, incrementing by 1.2:
def output = range[0.0, 6.0, 1.2]
//output> 0.0
// 1.2
// 2.4
// 3.6
// 4.8
// 6.0
rational
View sourcerational[n, num, denom]
The n
-bit rational value from integer numerator num
and denominator denom
.
Both num
and denom
must be encodable with n
-bits.
The result is invalid when both the numerator and the denominator are zero.
Rational
View sourceRational(nbits, x)
Holds if x
is an nbits
rational.
Example:
Query that checks that x
is of type Rational with a bit size of nbits
, a numerator of -5
, and a denominator of -7
:
def my_rational = rational[16, -5, -7]
def output(x) = my_rational(x) and Rational(16, x)
//output> 5/7
rational_convert
View sourcerational_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,)
RationalNumber
View sourceRationalNumber(x)
Holds if x
is a rational number.
Parameters
Parameter | Type | Description |
---|---|---|
x | RationalNumber | An integer value. |
Explanation
A RationalNumber
can be created with rational
, as shown in the examples below.
Examples
def R = rational[16, -5, -7]
ic rational_type_check(x in R) {
RationalNumber(x)
}
def R = int[8, 5]; uint[8, 5]; rational[16, -5, -7]
def output(x) = R(x) and RationalNumber(x)
//output> 5//7
See Also
regex_compile
View sourceregex_compile(regex, pattern)
Compile a regular expression to a pattern. If regex
is a pattern, rather than a string,
then pattern = regex
.
Example:
def p = regex_compile["^.*@.*$"]
pattern_match(p, "foo@example.com")
//output> () // true
regex_match
View sourceregex_match(regex, string)
Match string with a regular expression (string or pattern).
Note that if the entire string needs to be matched, then a leading ^
and
trailing $
are required in the regular expression.
Example:
regex_match("^.*@.*$", "a@b")
regex_match_all
View sourceregex_match_all[regex, input_string]
All the occurrences of a regular expression regex
(string or pattern)
in string
, including all the matches and offsets.
Each match is a pair (i, s)
with the character index i
where that matching string starts and
the matching string s
.
Example:
regex_match_all["(?<hour>\\d+):(?<minute>\\d+)",
"Appointment from 12:45 to 1:30"]
is equal to
{(19, "12:45"); (28, "1:30")}
rel:catalog:model (bound)
View sourcebound rel:catalog:model
Declare that rel:catalog:model
has type (String, String)
.
This declaration generates an IC ensuring that rel:catalog:model
contains
only tuples of type (String, String)
.
rel:catalog:model_creation_time (bound)
View sourcebound rel:catalog:model_creation_time
Declare that rel:catalog:model_creation_time
has type (String, DateTime)
.
This declaration generates an IC ensuring that rel:catalog:model_creation_time
contains
only tuples of type (String, DateTime)
.
rel:catalog:model_update_time (bound)
View sourcebound rel:catalog:model_update_time
Declare that rel:catalog:model_update_time
has type (String, DateTime)
.
This declaration generates an IC ensuring that rel:catalog:model_update_time
contains
only tuples of type (String, DateTime)
.
rel:integration:load_partitioned_csv
View sourcerel:integration:load_partitioned_csv[URI_string]
rel:integration:load_partitioned_csv[R]
This is the main in-language API for loading partitioned CSV data into a single logical relation.
For detailed information on CSV loading, see load_csv.
To load a partitioned CSV, specify the following:
:path
: The path to the first CSV partition, e.g."azure://storage.blob.core.net/container/file_1_of_24.csv"
. For more than one partition to get picked up, please note the naming schema: Name partitions using[...]_m_of_n[...]
, wherem
is the current partition andn
the total number of partitions (e.g.mycsv_1_of_16.csv
,mycsv_2_of_16.csv
, etc.).- Only the first partition should include header information.
- Make sure all partitions are stored under the same
:path
prefix.
The resulting relation is of the form (column_name, partition, line, value)
. partition, line
uniquely identifies each row in the CSV.
If errors occur, the resulting relation is of the form (:load_errors, partition, line, error_column, raw_line)
.
partition
and line
are UInt32s. To address them, please use uint[32, <number>]
.
If only a single partition is provided or data is directly passed into the load, the
resulting relation looks just like a load_csv
call with an added partition = uint[32, 1]
.
rel:mirror:argument
View sourcerel:mirror:argument[T]
rel:mirror:argument(T, tuple_position, value)
Maps the arguments of a relation T
to a new binary relation containing all the elements of T
keyed by their position in the argument tuple.
Examples
Pivot an arity-3 relation:
def output = rel:mirror:argument[{"first", "second, "third"}]
//output> (#1, "first")
// (#2, "second")
// (#3, "third")
rel:mirror:arity
View sourcerel:mirror:arity[R]
rel:mirror:precise_arity[R](v)
The specialized form of the arity of a relation.
rel:mirror:precise_arity[R]
is similar to rel:mirror:arity[R]
but only outputs the arities for which there are run-time values in R
.
Example:
def p = (1, 2, 3)
ic { rel:mirror:arity[p] = #3 }
ic { rel:mirror:precise_arity[p] = #3 }
def q = p ∩ (4, 5, 6) // empty
ic { rel:mirror:arity[q] = #3 }
ic { not exists(rel:mirror:precise_arity[q]) }
RelName
View sourceRelName(x)
Holds if x
is a relation name.
Examples:
Integrity constraint specifying that mymodule
always contains a RelName
and an integer:
def mymodule:f = 1
ic { subset(mymodule, (RelName, Int)) }
def output = mymodule
//output> (:f, 1)
relname_string
View sourcerelname_string[my_relname]
relname_string(my_relname, my_string)
Convert RelName (my_relname
) data into String data (my_string
).
Parameters
Parameter | Type | Description |
---|---|---|
my_relname | RelName | A valid RelName. |
my_string | String | A valid string. |
Explanation
The relation relname_string
maps a RelName
value to its corresponding String
value.
RelName
is a specialized data type version of the String
data type.
RelName
data types are used for metadata information.
Relation, module, and IC names are all stored as RelName
.
relname_string
can be used to:
- Verify that a RelName and string match.
relname_string(relation_name, string)
evaluates totrue
ifrelation_name
matchesstring
. Ifrelation_name
does not matchstring
,relname_string(relation_name, string)
evaluates tofalse
(the empty relation,{}
). - Convert a RelName to a string (
relname_string[relation_name]
provides shorthand for this use).
Using relname_string
to convert a String to a RelName is not yet supported.
Examples
Verify that a RelName matches a string.
relname_string(:rel, "rel")
//evaluates to `true` because the RelName `:rel` matches the string `"rel"`.
Convert RelName :employees
to string:
def output(x) = relname_string(:employees, x)
//output> "employees"
Convert RelName :employees
to string using equivalent shorthand:
def output = relname_string[:employees]
See Also
remainder
View sourceremainder[x, y]
remainder(x, y, r)
x % y
Remainder from truncated division.
Parameters
Parameter | Type | Description |
---|---|---|
x | Number | Dividend. Must be grounded. |
y | Number | Divisor. Must be grounded. |
r | Number | Remainder. |
Not all numeric values can be mixed with each other. The following combinations work:
x | y | r |
---|---|---|
Number | Same as x . | Same as x . |
SignedInteger , UnsignedInteger | SignedInteger , UnsignedInteger | SignedInteger[#n] or UnsignedInteger[#n] , where n is the greater of the number of bits in the types of x or y . Signedness matches the type of x . |
FloatBinary , FixedDecimal | SignedInteger[#64] | Same as x . |
SignedInteger[#64] | FloatBinary , FixedDecimal | Same as y . |
Rational | SignedInteger[#64] | Rational[n] , where n is the greater of the number of bits in the types of x and y . |
SignedInteger[#64] | Rational | Rational[n] , where n is the greater of the number of bits in the types of x and y . |
Explanation
remainder
is the remainder of x
after truncated division of y
.
That is, remainder[x, y]
is equivalent to x - (y * trunc_divide[x, y])
.
x % y
is equivalent to remainder[x, y]
.
r
has the same sign as x
, and is smaller in magnitude than y
.
The value for r
is always exact.
remainder[x, y]
is defined when either the types of x
and y
are the same, or
either operand is of type SignedInteger[#64]
or FloatBinary[#64]
.
remainder
is false
(empty) when y = 0
for integer arguments.
Examples
Compute remainder of integer divided by integer using %
.
def output = 8 % 3
//output> 2
Compute remainder of integer divided by integer using remainder
:
def output = remainder[-8, 3]
//output> -2
Compute remainder of integer divided by negative integer using full expression:
def output(r) = remainder(8, -3, r)
//output> 2
Compute remainder of rational divided by negative integer:
def output = remainder[rational[64, 8, 3], -2]
//output> 2/3
Confirm that remainder is false
(empty) when y
is 0
:
def output = empty(remainder[6, 0])
//output> () // true
reverse_sort
View sourcereverse_sort[R]
Reverse Sort
Like sort
, except the ordering is reversed.
Example:
def sample = {'a'; 'b'; 'c'}
def output = reverse_sort[sample]
//output> (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]]
//output> (:g, 1, 'c')
// (:g, 2, 'b')
// (:g, 3, 'a')
// (:h, 1, 'f')
// (:h, 2, 'e')
// (:h, 3, 'd')
right_override
View sourceright_override[R, S]
R ++> S
Right override is identical to left override, except the arguments are swapped.
R ++> S
contains all of S
, plus all the tuples in R
whose key is not in S
.
There are two equivalent ways to think about R ++> S
:
(1) R
is providing default values for keys that are missing in S
.
(2) The entries in S
are overriding the entries in R
.
A few examples to illustrate the difference with left-override:
Example | Value |
---|---|
2 ++> 3 | 3 |
(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) |
round
View sourceround[mode, x]
round(mode, x, r)
Round x
to an integer according to the given rounding mode. The rounded number is of the same data type as x
.
Parameters
Parameter | Type | Description |
---|---|---|
mode | RelName | Mode for rounding. Must be grounded. |
x | Number | Number to be rounded. Must be grounded. |
r | Number | Result of rounding x . Same type as x . |
Available Modes
mode | Description |
---|---|
:ROUND_UP | Round up to the nearest integer. |
:ROUND_DOWN | Round down to the nearest integer. |
:ROUND_NEAREST | Round to the nearest integer, with ties (fractional values of 0.5) being rounded to the nearest even integer. |
:ROUND_NEAREST_TIES_AWAY | Round to the nearest integer, with ties rounded away from zero. |
:ROUND_NEAREST_TIES_UP | Round to the nearest integer, with ties rounded toward positive infinity. |
:ROUND_TO_ZERO | Round toward zero to the nearest integer. |
Examples
Round nearest float:
def output = round[:ROUND_NEAREST, -8.555]
//output> 9.0
Round up rational:
def output = round[:ROUND_UP, rational[64, 8, 3]]
//output> 3/1
Round down float using full expression:
def output(r) = round(:ROUND_DOWN, 8.4, r)
//output> 8.0
Round nearest float, showing ties away and ties up:
def output:away = round[:ROUND_NEAREST_TIES_AWAY, -8.5]
def output:up = round[:ROUND_NEAREST_TIES_UP, -8.5]
//output> (:away, -9.0)
// (:up, -8.0)
Round to 0:
def output = round[:ROUND_TO_ZERO, -8.5]
//output> -8.0
See Also
floor
, floor_to_int
, ceil
, trunc
, and trunc_to_int
.
round
View sourceround[x]
round(x, r)
Round x
to the nearest integer. The rounded number is of the same data type as x
.
Parameters
Parameter | Type | Description |
---|---|---|
x | Number | Number to be rounded. Must be grounded. |
r | Number | Result of rounding x . Same type as x . |
Explanation
round[x]
rounds to the nearest integer, with ties rounded to the nearest even integer.
It is equivalent to round[:ROUND_NEAREST, x]
.
For details see the docstring for round(mode, x, r)
.
Example
Rounding a floating-point number:
def output = round[9.7]
//output> 10.0
Rounding a fractional:
def output = round[rational[64, 7, 3]]
//output> 2/1
sample_standard_deviation
View sourcesample_standard_deviation[R]
sample_stddev[R]
Sample standard deviation of (the last argument of) the relation R
.
sample_stddev
View source
see: sample_standard_deviation
sample_zscore_normalization
View sourcesample_zscore_normalization[R]
Z-score normalization (sample) of (the last argument of) the relation R
.
Often simply referred to as ‘standardization’.
Second
View sourceSecond[n]
DEPRECATED
This function is deprecated and should be avoided. It will be removed soon.
Please use the Second constructor, ^Second
, instead.
Create a period of n
seconds.
second
View sourcesecond[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)]
//output> 2
// 5
def output = second[(1, 2); (3, "abc")]
//output> 2
// "abc"
SignedInt
View sourceSignedInt(nbits, x)
DEPRECATED
This relation is deprecated and should be avoided. It will be removed soon.
Please use SignedInteger
instead. Note that SignedInteger
takes a specialized integer
for nbits
.
Holds if x
is an nbits
signed integer.
Examples:
Integrity constraint that tests whether x
is an 8-bit signed integer:
def R = int[8, 5]
ic signed_type_check(x in R) {
SignedInt(8, x)
}
SignedInteger
View sourceSignedInteger(#nbits, x)
Holds if x
is an nbits
signed integer, where nbits
is a specialized integer.
SignedInteger is a binary relation.
SignedInteger[#64] is a unary relation.
Examples:
Integrity constraint that tests whether x
is an 8-bit signed integer:
def R = int[8, 5]
ic signed_type_check(x in R) {
SignedInteger[#8](x)
}
Check whether x
is any signed integer:
def x = int[16, 5]
def output = SignedInteger[_](x)
SignedRational
View sourceSignedRational(#nbits, x)
Holds if x
is an nbits
rational.
Parameters
Parameter | Type | Description |
---|---|---|
#nbits | #(Int) | A specialized integer (must be a valid bit size). |
x | Rational | A rational value. |
Examples
Query that checks that x
is of type SignedRational with a bit size of nbits
, a numerator of -5
, and a denominator of -7
:
def my_rational = rational[16, -5, -7]
def output(x) = my_rational(x) and SignedRational(#16, x)
//output> 5/7
See Also
sin
View sourcesin[x]
sin(x, s)
Sine of x
, where x
is an angle given in radians.
Parameters
Parameter | Type | Description |
---|---|---|
x | SignedInteger[#64] , FloatBinary[#64] | Angle in radians. Must be grounded. |
s | FloatBinary[#64] | Sine of x . |
Currently, only 64-bit float and integer values for x
are supported.
Examples
Calculate the sine of π/2::
def output = sin[pi_float64/2]
//output> 1
Calculate the sine of 5π/6:
def output = sin[5 * pi_float64/6]
//output> 0.49999999999999994
See Also
asin
, sinh
, asinh
, cos
, acos
, cosh
, acosh
, tan
, atan
, tanh
, and atanh
.
sinh
View sourcesinh[x]
sinh(x, sh)
Hyperbolic sine. sh
is the hyperbolic sine of x
.
Parameters
Parameter | Type | Description |
---|---|---|
x | FloatBinary[#64] , SignedInteger[#64] | Hyperbolic angle. Must be grounded. |
sh | FloatBinary[#64] | Hyberbolic sine of x . |
Explanation
Only 64-bit float and 64-bit integer values for x
are supported.
Examples
Calculate the hyperbolic sine of 7:
def output = sinh[7]
//output> 548.3161232732465
Calculate the hyperbolic sine of -1 using full expression:
def output(x) = sinh(-1, x)
//output> -1.1752011936438014
Confirm that 548.3161232732465 is the hyperbolic sine of 7:
def output = sinh(7, 548.3161232732465)
//output> () // true
See Also
sort
View sourcesort(R, index, x...)
Enumerate the tuples in a relation.
Parameters
Parameter | Type | Description |
---|---|---|
R | Relation | Relation to be enumerated. Must be grounded. |
index | Int | The new enumeration index starting at 1. |
x... | Tuples | A tuple in R associated with the new index index . |
Explanation
sort
is an alias for enumerate
.
The purpose of sort
is to generate a global index across all tuples in R
.
It should not be used to sort tuples by value, as the sorting order across data types and tuple lengths is not well defined.
The enumeration is deterministic meaning enumerating the same tuples will always produce the same result.
For more information on how tuples are indexed, see the docstring for enumerate
.
See Also
soundex
View sourcesoundex[string_value]
soundex
returns a four-letter encoding the phonetic representation of string_value
.
soundex
lets you compare words and sentences based on how they sound in English.
string_value
could be any arbitrary long string, but only the first few syllables are
considered for the result.
Examples:
def output = soundex["Smith"]
//output> s530
def output = soundex["Smythe"]
//output> s530
def output = soundex["Christina"]
//output> c623
def output = soundex["Cristine"]
//output> c623
Here is a simple illustration. Consider the following:
def my_favorite_bands = { "Metallica"; "Iron Maiden"; "Wolfheart"; "Insomium" }
def do_I_like = "Mee ta li ka"
def output = exists({ y : soundex[my_favorite_bands][y] and equal(y, soundex[do_I_like]) })
The script above evaluates to true
since "Mee ta li ka"
and
"Metallica"
have the same soundex code.
spread
View sourcespread[mode, R, value]
spread(mode, R, value, x..., spread)
Spread value
to the tuples in relation R
, either evenly or proportionally to their
weight, which is the last element in each tuple.
Parameter
Parameter | Type | Description |
---|---|---|
mode | RelName | :even or :ratio . |
R | Relation | Source relation. Must be grounded. |
value | Int , FixedDecimal | Integer or decimal to be divided among tuples as spread . Must be grounded. |
x... | Tuple | A tuple in R . |
spread | Float | Spread associated with x... . |
Explanation
spread
takes a relation R(x...)
and produces a relation with the tuples (x..., spread)
where the last element of each tuple (spread
)
is a spread of value
distributed among tuples.
When mode
is :even
, spread
is value
divided evenly among tuples.
When mode
is :ratio
, spread
is value
divided proportionally to a tuple’s
weight — the last element in each tuple.
spread
can be either an integer or a decimal depending on the type of value
.
That is, if you use a decimal for value
, spread
behaves like FixedDecimal_spread
.
If you use an integer for value
, spread
behaves like either int_spread_by_even
or int_spread_by_ratio
, depending on mode
.
spread
is empty if value
is negative.
Examples
Spread using a value
that is a decimal.
Note that spread
is a decimal with the same number of places as value
, just as would be the case with FixedDecimal_spread
:
def R = {("Atlanta", 50);
("Seattle", 80);
("San Francisco", 10)}
def output = spread[:even, R, decimal[#64, #3, 31.0] ]
//output> Atlanta, 50, 10.334
// San Francisco, 10, 10.333
// Seattle, 80, 10.333
Spread using a value
that is an integer.
Note that spread
is an integer:
def R = {("Atlanta", 50);
("Seattle", 80);
("San Francisco", 10)}
def output = spread[:even, R, 31]
//output> Atlanta, 50, 11
// San Francisco, 10, 10
// Seattle, 80, 10
Spread using full expression, using a decimal as spread
:
def R = {("Miles Davis", 65); ("Jimmy Smith", 76); ("Ornette Coleman", 85)}
def output = spread[:ratio, R, decimal[#64, #3, 88.55]]
//output> Jimmy Smith, 29.778
// Miles Davis, 25.468
// Ornette Coleman, 33.304
See Also
int_spread_by_ratio
, int_spread_by_even
, and FixedDecimal_spread
.
squared
View sourcesquared[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)}
squared_deviation
View sourcesquared_deviation[R]
Squared deviation: squared deviation from the mean of (the last argument of) the relation R
.
starts_with
View sourcestarts_with(s, prefix)
True if and only if the specified string s
begins with the given prefix prefix
.
Examples:
starts_with("abc", "ab") // true
starts_with("abc", "bc") // false
starts_with("abc", "abcd") // false
starts_with("abc", "Ab") // false
string
View sourcestring[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"
String
View sourceString(x)
Holds if x
is a String
. Strings are specified by double quotes, for example, "abc"
.
Examples:
Integrity constraint that tests whether x
is of type String
:
def R = "foo"
ic string_type_check(x in R) {
String(x)
}
Schema defined in a relation using String
:
def myrelation(x in String, y in Int) {
x = "abc" and y = 123
}
def output = myrelation
//output> (abc, 123)
string_join
View sourcestring_join[separator, R]
string_join(separator, R, new_string)
Concatenate the string values in the binary relation R
into one string and insert the string, separator
, between two adjacent strings.
Parameters
Parameter | Type | Description |
---|---|---|
separator | Char or String | Character or String used to separate adjacent strings. Must be grounded. |
R | Relation | A binary relation containing tuples of the form (Int, String) . Must be grounded. |
new_string | String | Resulting string containing all the strings in R separated by separator . |
Explanation
The binary relation R
can only contain tuples (index, text)
with the signature (Int, String)
.
The purpose of the two elements are:
- The integer
index
represents the order of the strings to be joined, and serves as the sort key for concatenation. - The string
text
represents the Strings that will be concatenated together.
If R
is empty, the expression string_join[separator, R]
is false
and no new string is created.
Examples
Concatenate using ", "
as separator:
def output = string_join[", ", {(1, "a"); (2, "b"); (3, "c")}]
//output> "a,b,c"
Concatenate using the character ' '
as separator:
def output = string_join[' ', {(1, "hello"); (2, "world")}]
//output> "hello world"
Using string_join
and sort
to order a set of Strings alphabetically and join them together with "->"
as separator:
def output = string_join["->", sort[{"x"; "y"; "z"}]]
//output> "x->y->z"
See Also
string_length
, string_replace
, string_replace_multiple
, string_split
, and string_trim
.
string_length
View sourcestring_length[string]
DEPRECATED
This function is deprecated. Use num_chars[string]
or num_bytes[string]
,
depending on your need.
Example:
string_length["foo"] = 3
string_replace
View sourcestring_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"
string_replace_multiple
View sourcestring_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
.
string_split
View sourcestring_split[delimiter, text]
Split the string text
into the substrings delimited by delimiter
(and the
start/end of text
).
The expression string_split[delimiter, string]
evaluates to a relation of the format
(index, sub_string)
where index
is the substring’s position of type Int
and
sub_string
is the matched substring of type String
.
delimiter
can be a String
or a Char
.
Example:
string_split['@', "user@email.com"] = {(1, "user"); (2, "email.com")}
string_split[" ", "a b c"] = {(1, "a"); (2, "b"); (3, ""); (4, "c")}
string_trim
View sourcestring_trim[s]
To remove leading and tailing white spaces in given string s
.
Example:
string_trim[" Good Day!!! "] = "Good Day!!!"
subset
View sourcesubset(R, S)
R ⊆ S
R
is a subset of S
if all facts in R
are 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 ofR
. IfR
also contains facts of a different arity, then the implication remains true, even whenR ⊈ S
. -
subset(R, S)
, defined asforall(xs... where R(xs...) : S(xs...))
, is true only if there exists no fact inR
, of any arity, that is not also inS
.
substring
View sourcesubstring[mystring, i, j]
substring(mystring, i, j, substring)
Find a substring (substring
) within mystring
that starts at index i
and ends at index j
.
Parameters
Parameter | Type | Description |
---|---|---|
mystring | String | Source text. Must be grounded. |
i | SignedInteger , UnsignedInteger | The position where substring begins. Must be grounded. |
j | SignedInteger , UnsignedInteger | The position where substring ends. Must be grounded. |
substring | String | A string that begins at the i -th character and ends at the j -th character. |
Explanation
The index of a string’s first character is 1.
When i
and j
are out of bounds on the same end, or i
> j
, the empty string is returned.
If i < 1
the substring will start with the first character in mystring
.
If j > length[mystring]
the substring ends with the last character in mystring
.
Examples
Get the two-character string beginning with position 2
:
def output = substring["abcd", 2, 3]
//output> bc
Get a two-character string beginning with position 2
using full expression:
def output(x) = substring("中文例子", 2, 3, x)
//output> 文例
Substring that returns empty because i
> j
:
def output = substring["abcd", 3, 2]
//output> ""
Substring that returns empty because i
and j
are out of bounds:
def output = substring["abcd", 5, 7]
//output> ""
Get the substring containing the first three characters with i
out of bounds:
def output = substring["abcd", -2, 3]
//output> abc
Get the substring containing the characters starting at index 2
and with j
out of bounds:
def output = substring["abcd", 2, 7]
//output> bcd
See Also
substring_bytes
, starts_with
, ends_with
, and string_replace
.
substring_bytes
View sourcesubstring_bytes[string, index1, index2]
Extracts substring of a string
between the byte range [index1:index2]
(both inclusive).
The byte index starts with 1.
When index1
and index2
are out of bounds on the same end, or index2
< index1
,
the empty string is returned.
Otherwise, both indices are clamped in range.
Use substring
to extract substrings by character indices.
Examples:
substring_bytes["abcd", 2, 3] = "bc"
substring_bytes["abcd", 3, 2] = ""
substring_bytes["word", 0, 10] = "word"
Note that non-ASCII characters require usually more than one byte per character:
substring_bytes["中文例子", 1, 6] = """中文"""
subtract
View sourcesubtract[x, y]
subtract(x, y, d)
x - y
Subtraction of one number from another. Subtraction of a date, datetimes, and periods.
Parameters
Numeric Data
Parameter | Type | Description |
---|---|---|
x | Number | Subtrahend. |
y | Number | Minuend. |
d | Number | Difference x - y . |
Not all numeric values can be mixed with each other. The following combinations work:
x | y | d |
---|---|---|
Number | Same as x | Same as x |
SignedInteger[#64] | SignedInteger[#128] , FloatBinary[#64] , FixedDecimal , Rational | Same as y |
SignedInteger[#128] , FloatBinary[#64] , FixedDecimal , Rational | SignedInteger[#64] | Same as x |
Two of the three arguments need to be grounded. Valid grounding combinations are as follows:
x
andy
.x
andd
.y
andd
.
Time Data
Parameter | Type | Description |
---|---|---|
x | Date , DateTime , date period, time period | Minuend. |
y | Date , DateTime , date period, time period | Subtrahend. |
d | Date , DateTime , date period, time period | Difference x - y . |
The following combinations work:
x | y | d |
---|---|---|
date period, time period | Same date period, time period as x | Same Date period, time period as x |
DateTime | date period, time period | DateTime |
DateTime | DateTime | Time period in Millisecond |
Date | date period | Date |
Date | Date | date period in Day |
Two of the three arguments need to be grounded. Valid grounding combinations are as follows:
x
andy
.x
andd
.y
andd
.
Explanation
subtract
maps the pair x
, y
to d
, which is the difference x - y
.
In procedural languages, usually x
and y
are given.
In Rel — a declarative language — subtraction can be thought of as a mapping where x
and y
are the keys and d
is the value, which is functionally dependent on x
and y
.
However, with subtraction — subtract(x, y, d)
— it is sufficient to know any two of the three arguments.
The third argument can always be inferred.
Usually x
and y
are given, but knowing x
and d
is enough to infer y
.
Examples
Subtract two numerals using -
:
def output = 8 - 5
//output> 3
Subtract a float from an integer using subtract
:
def output = subtract[7, 5.25]
//output> 1.75
Subtract two floats using full expression:
def output(x) = subtract(8.5, 5.25, x)
//output> 3.25
Subtract a rational from an integer:
def output = x - rational[16, 2, 3]
//output> 4/3
Calculate integer subtracted by providing x
and d
:
def output(y) = subtract(2899, y, 2865)
//output> 34
Subtraction of Time
Subtract a time period and a date period from a timestamp:
def output:yesterday = datetime_now - ^Day[1]
def output:last_hour = datetime_now - ^Hour[1]
//output> (:last_hour, 2022-11-17T13:01:52.537Z)
// (:yesterday, 2022-11-16T14:01:52.537Z)
Subtract a timestamp from a timestamp and get the difference in milliseconds. Note that the second date is defined in a different time zone and the time difference is 58 hours, or 136800000 milliseconds:
def output = 2021-10-12T01:00:00+00:00 - 2021-10-10T01:00:00+10:00
//output> 136800000
Subtract weeks from a date:
def output = 2024-01-10 - ^Week[2]
//output> 2023-12-27
Subtract two dates from each other and retrieve the number of days between them. Here, the date period is negative because the second date occurs later:
def output = 2023-12-30 - 2024-01-10
//output> -11
Calculate date subtracted by providing date and resulting period:
def output(y) = subtract(2022-10-01, y, ^Day[10])
//output> 2022-09-21
Subtract 2 seconds from 6 seconds:
def output = ^Second[6] - ^Second[2]
//output> 4
See Also
suffix_join
View sourcesuffix_join[R, S]
R :> S
The suffix join (or restriction) of R
to S
consists of the tuples (x..., y...)
in R
where the suffix (y...)
is in S
.
That is, R :> S
contains the tuples in R
that have a suffix in S
.
Example | Normalized |
---|---|
edge :> n | x, y: edge(x, y) and y = n |
parent :> female | x, y: parent(x, y) and female(y) |
account_balance :> positive | x, 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
wherejson
is[ {"a": 1, "b": 2}, {"a": 3, "b": 4, "c": 6} ]
has value[ {"b": 2}, {"b": 4, "c": 6} ]
-
json :> (:b, even)
wherejson
is[ {"a": 1, "b": 2}, {"a": 3, "b": 4, "c": 6} ]
has value[ {"b": 2}, {"b": 4} ]
sum
View sourcesum[R]
sum(R, s)
Σ[R]
Σ(R, s)
Sum of the last element of all tuples in a relation.
Parameters
Parameter | Type | Description |
---|---|---|
R | Relation | Source relation. Must be grounded. |
s | Number | The sum of the last element of R . |
Explanation
sum
aggregates over all tuples in R
whose last element is numeric.
Tuples in R
can have different lengths, and the length may vary from tuple to tuple.
Tuples with a non-numeric last element are ignored.
For example, if R
contains key-value pairs, sum[R]
calculates the sum of values for R
.
Note that sum
groups the tuples by the data type of the final numeric element.
Typically, sum
is used when the last elements of each tuple have the same type.
If R
is empty, sum[R]
is false
(empty).
To get 0 instead, use left override, as in sum[R] <++ 0
.
Examples
Calculate the sum of integers:
def salary = {("John", 10) ; ("Mary", 20); ("Paul", 17) ; ("Peter", 15) }
def output = sum[salary]
//output> 62
Calculate the sum of R
for each data type:
def R = {(1, "1"); (2, 2); (3, 3.0); (4, 4)}
def output = sum[R]
//output> 3.0
6
Calculate the sum of R
using full expression:
def R = {("A", 7.5); ("B", 8.6); ("C", 9.7)}
def output(s) = sum(R, s)
//output> 25.8
Calculate the total salary by department using group-by:
def department = {"A"; "B"; "C" }
def member = {("A", "John"); ("B", "Mary"); ("A", "Paul"); ("C" , "Peter"); ("C", "Tran")}
def salary = {("John", 126) ; ("Mary", 90); ("Paul", 117); ("Peter", 115); ("Tran", 145)}
def output = d in department: sum[salary[p] for p in member[d]]
//output> "A", 243
// "B", 90
// "C", 260
See Also
sum_int
View sourcesum_int[R]
sum_int(R, si)
Sum over the last elements in the tuples of R
, which must be integers.
Parameters
Parameter | Type | Description |
---|---|---|
R | Relation | A grounded relation. The last element of every tuple must be an integer. |
si | SignedInteger[#64] | The integer sum of the last element of R . |
Explanation
sum_int
sums over the last elements of every tuple in R
.
Every last element must be an integer.
If this is not the case, invoking sum_int[R]
will trigger an error.
Tuples in R
can have different lengths, and only the last element in each tuple is used for the sum.
In contrast to sum
, sum_int[R]
evaluates to 0
if R
is empty.
Examples
Find the integer sum of a relation:
def R = {("Oakland", 22); ("Fresno", 11); ("Palo Alto", 15); ("Eureka", 40)}
def output = sum_int[R]
//output> 88
Evaluate the sum of a relation with various tuple lengths:
def salary = {("John", 10) ; ("Mary", "Smith", 20); }
def output = sum_int[salary]
//output> 30
The sum over an empty relation is zero:
def output = sum_int[{}]
//output> 0
See Also
tan
View sourcetan[x]
tan(x, t)
Tangent. t
is the tangent of x
, where x
is in radians.
Parameters
Parameter | Type | Description |
---|---|---|
x | FloatBinary[#64] , SignedInteger[#64] | Angle in radians. Must be grounded. |
t | FloatBinary[#64] | Tangent of x . |
Defined for non-infinite x
.
Only 64-bit float and 64-bit integer values for x
are supported.
Examples
Calculate the tangent of π/4:
def output = tan[pi_float64/4]
//output> 0.9999999999999999
Convert degrees to radians and calculate tangent using full expression:
def x = deg2rad[90]
def output(t) = tan(x, t)
//output> 16331239353195370.0
Confirm that 0.9999999999999999 is the tangent of π/4:
def output = tan(pi_float64/4, 0.9999999999999999)
//output> () // true
See Also
tanh
View sourcetanh[x]
tanh(x, th)
Hyperbolic tangent. th
is the hyperbolic tangent of x
.
Parameters
Parameter | Type | Description |
---|---|---|
x | FloatBinary[#64] , SignedInteger[#64] | Hyperbolic angle. Must be grounded. |
th | FloatBinary[#64] | Hyberbolic tangent of x . |
Explanation
Only 64-bit float and 64-bit integer values for x
are supported.
Examples
Calculate the hyperbolic tangent of 7:
def output = tanh[7]
//output> 0.9999983369439447
Calculate the hyperbolic tangent of -1 using full expression:
def output(x) = tanh(-1, x)
//output> -0.7615941559557649
Confirm that 0.9999983369439447 is the hyperbolic tangent of 7:
def output = tanh(7, 0.9999983369439447)
//output> () // true
See Also
top
View sourcetop[k, R]
top(k, R, index, x...)
Select the top k
tuples of relation R
according to the lexicographic order of R
and add enumeration.
Parameters
Parameter | Type | Description |
---|---|---|
R | Relation | Source relation. Must be grounded. |
k | Int | Number of tuples to enumerate from the top of R . Must be grounded. |
index | Int | The new enumaration index starting at 1. |
x... | Tuple | A tuple in R associated with the new index index . |
Explanation
top
is enumerate
restricted to the first k
tuples of R
.
top
first puts the tuples of R
in lexicographical order and then limits the result to the first k
tuples.
For details on lexicographical ordering — particularly across data types — see enumerate
.
Similar to enumerate
, top
takes a relation R(x...)
and produces a relation with the tuples (index, x...)
,
where the first element of each tuple (index
) is an integer index that enumerates the top k
tuples
in the original relation R
.
If k
is bigger than the number of tuples in the relation R
, then top[k, R]
is equivalent to enumerate[R]
.
The relation R
can contain tuples of various sizes.
top[k, R]
supports group-bys in R
but not in k
.
For example, the following is supported:
def output[g] = top[k, R[g]]
However, the following is not supported:
def output[g] = top[k[g], R]
Examples
Apply top
to a relation with arity-1 tuples:
def output = top[2, {'a'; 'b'; 'c'; 'd'}]
// output> (1, 'a')
// (2, 'b')
Apply top
to a relation with arity-2 tuples:
def R = {('a', 1); ('b', 2); ('c', 3); ('d', 4); ('e', 5)}
def output = top[3, R]
//output> 1, a, 1
// 2, b, 2
// 3, c, 3
See Also
bottom
, enumerate
, sort
, and reverse_sort
.
total
View sourcetotal(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.
transpose
View sourcetranspose[R]
Transpose a binary relation (swap the two arguments).
Example:
def output = transpose[{(1, 2); (3, 4)}]
//output> (2, 1)
// (4, 3)
trunc
View sourcetrunc[x]
trunc(x, t)
Round toward zero to the nearest integer.
Parameters
Parameter | Type | Description |
---|---|---|
x | Number | Number to be rounded toward zero. Must be grounded. |
t | Int | Truncated x . |
Return type is the same as x
.
Explanation
Rounds toward zero for both positive and negative x
.
Examples
Truncate float:
def output = trunc[3.9]
//output> 3.0
Truncate negative float using full expression:
def output(t) = trunc(-4.9, t)
//output> -4.0
Truncate rational:
def output = trunc[rational[64, 27, 5]]
//output> 5/1
See Also
floor
, floor_to_int
, ceil
, trunc_to_int
, and round
.
trunc_divide
View sourcetrunc_divide[x, y]
trunc_divide(x, y, q)
x ÷ y
Division of two numbers, rounding the result to the nearest integer toward zero.
Parameters
Parameter | Type | Description |
---|---|---|
x | Number | Numerator. Must be grounded. |
y | Number | Denominator. Must be grounded. |
q | Number | Truncated quotient x / y . |
Not all numeric values can be mixed with each other. The following combinations work:
x | y | q |
---|---|---|
SignedInteger[#64] | SignedInteger[#64] | SignedIneger[#64] |
SignedInteger[#64] | FloatBinary[#64] | FloatBinary[#64] |
FloatBinary[#64] | SignedInteger[#64] , FloatBinary[#64] | FloatBinary[#64] |
Rational | SignedInteger[#64] | SignedInteger[#64] |
FixedDecimal | SignedInteger[#64] | Same as x |
Explanation
trunc_divide
maps the pair x
, y
to q
, which is the truncated quotient x/y
.
Similar to divide
and in contrast to add
and subtract
, x
and y
need to be grounded and specified by the user.
Specifying only x
and q
or only y
and q
is not sufficient, because the system can’t compute the inverse.
trunc_divide
is false
(empty) when y = 0
for integer arguments.
Examples
Use truncated division to divide an integer by another integer using ÷
:
def output = 5 ÷ 2
//output> 2
Use truncated division to divide an integer by another integer using trunc_divide
:
def output = trunc_divide[5, 2]
//output> 2
Use truncated division to divide a negative integer by a positive integer:
def output = trunc_divide[-5, 2]
//output> -2
Use truncated division to divide a decimal by an integer using full expression:
def output(x) = trunc_divide(5.1, 2, x)
//output> 2.0
Use truncated division to divide a rational by an integer using full expression:
def output(t) = trunc_divide(rational[64, 26, 3], 2, t)
//output> 4
trunc_to_int
View sourcetrunc_to_int[x]
trunc_to_int(x, t)
Convert float to integer, truncating.
Parameters
Parameter | Type | Description |
---|---|---|
x | Float | Number to be rounded down. Must be grounded. |
t | Int | Truncated x , integer. |
Explanation
Rounding goes toward zero for both postivie and negative x
.
Examples
Convert float to integer, truncating:
def output = trunc_to_int[3.1]
//output> 3
Convert negative float to integer, truncating, using full expression. Note that rounding goes toward zero.
def output = trunc_to_int[-3.1]
//output> -3
Confirm that trunc_to_int
returns false
(empty) when x
is an integer:
def output = trunc_to_int[3]
//output> // false
See Also
floor
, floor_to_int
, ceil
, trunc
, and round
.
uint
View sourceuint[n, v]
The n
-bit unsigned integer value from the positive integer value v
.
n
must be among 8, 16, 32, 64, and 128 and v
is encodable with n
-bits.
Examples:
uint[8, 42] = 42
empty(uint[128, -300])
empty(uint[8, 300])
uint128_hash_value_convert
View sourceuint128_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.
uint128_uint64_truncate
View sourceuint128_uint64_truncate[v]
Truncates v
of type UInt128
to a UInt64
number.
Truncates the high order bits in v
and converts the remaining bits to UInt64.
Truncate always succeeds. For values larger than 2^64, consists of only the lower bits.
Examples:
uint128_uint64_truncate[uint128[1]] = 1
uint128_uint64_truncate[uint128[2] ^ 64 + uint128[1]] = 1
unpack
View sourceunpack(v, x₁, ..., xₙ)
Unpacks a packed structure v
into its arguments x₁, ..., xₙ
.
unpack
cannot be used with point-free syntax.
Direct usage of unpack
should be avoided, as it serves primarily as a low-level
interface for value types.
UnsignedInt
View sourceUnsignedInt(nbits, x)
DEPRECATED
This relation is deprecated and should be avoided. It will be removed soon.
Please use UnsignedInteger
instead. Note that UnsignedInteger
takes a specialized integer
for nbits
.
Holds if x
is an unsigned integer of the bit length nbits
.
Example:
Integrity constraint that tests whether x
is a 32-bit unsigned integer:
def my_unsigned_int = uint[32, 1234]
ic my_unsigned_ic(x) {
my_unsigned_int(x) implies UnsignedInt(32, x)
}
UnsignedInteger
View sourceUnsignedInteger(#nbits, x)
Holds if x
is an nbits
unsigned integer, where nbits
is a specialized integer.
UnsignedInteger is a binary relation.
UnsignedInteger[#64] is a unary relation.
Examples:
Integrity constraint that tests whether x
is an 8-bit unsigned integer:
def R = uint[8, 5]
ic unsigned_type_check(x in R) {
UnsignedInteger[#8](x)
}
Check whether x
is any unsigned integer:
def x = uint[16, 5]
def output = UnsignedInteger[_](x)
uppercase
View sourceuppercase[string_or_char]
A string where all the characters are converted to uppercase. If a character is already uppercase or has no uppercase version, it remains unchanged.
Example:
def output = uppercase["aB1c"]
//output> "AB1C"
def output = uppercase['â']
//output> 'Â'
uppercase
does not take a locale option and does not handle local-specific case mapping
rules.
uuid_string
View sourceuuid_string[v]
Convert a UInt128
, Hash
or rel:base:UUID
value to the standard UUID string format.
Example:
uuid_string[0x22b4a8a1e5484eeb927060426d66a48e] = "22b4a8a1-e548-4eeb-9270-60426d66a48e"
Week
View sourceWeek[n]
DEPRECATED
This function is deprecated and should be avoided. It will be removed soon.
Please use the Week constructor, ^Week
, instead.
Create a period of n
weeks.
weighted_mean
View sourceweighted_mean[R, W]
weighted_mean(R, W, wm)
The weighted mean of the last element of each tuple in a relation R
with weights defined by W
.
Parameters
Parameter | Type | Description |
---|---|---|
R | Relation | A relation whose last elements contain numeric data types and whose first elements match W . Must be grounded. |
W | Relation | Weight for weighted mean. A relation whose last elements contain numeric data types and whose first elements match R . Must be grounded. |
wm | Number | The weighted mean of R . |
Explanation
The weighted mean of a relation R
is the sum of the last elements in each tuple of R
,
weighted by the last element of the corresponding tuple in W
.
A tuple in R
corresponds to a tuple in W
if the first elements of the tuples match
— that is, they have the same key.
weighted_mean
aggregates over all tuples in R
whose last element is numeric.
Tuples in R
can have different lengths, and the length may vary from tuple to tuple.
Tuples with a non-numeric last element are ignored.
Note that weighted_mean
groups the tuples by the data type of the last element.
This may cause unexpected results when used in relations with values of mixed types.
Typically, weighted_mean
is used when the last elements of each tuple have the same type.
Examples
Calculate weighted mean of a relation:
def inputs = {(:class_participation , 90); (:assignment_1, 85); (:assignment_2, 81); (:midterm, 76); (:final, 83)}
def weights = {(:class_participation, 10); (:assignment_1, 20); (:assignment_2, 20); (:midterm, 20); (:final, 30)}
def output = weighted_mean[inputs, weights]
//output> 82.3
Calculate weighted mean when the arities of R
and W
are different:
def R = {(1, "cp", 90); (2, "a1", 85); (3, "a2", 81); (4, "mt", 76); (5, "f", 83)}
def W = {(1, 10); (2, 20); (3, 20); (4, 20); (5, 30)}
def output = weighted_mean[R, (k1, k2, v: W(k1, v) and Any(k2))]
//output> 82.3
Calculate weighted mean when the arities of R
and W
are different:
def R = {(1, 'a', 100, 90); (2, 'a', 200, 85); (3, 'b', 300, 81); (4, 'c', 400, 76); (5, 'b', 500, 83)}
def W = {(1, 'a', 10); (2, 'a', 20); (3, 'b', 20); (4, 'c', 20); (5, 'b', 30)}
def output = weighted_mean[R, (n, c: _, W[n, c])]
//output> 82.3
See Also
geometric_mean
, harmonic_mean
, mean
, mode
, max
, min
, sum
, and product
.
xor
View sourceF xor G
F ⇎ G
F ⊻ G
Exclusive OR, for boolean (arity 0, true or false) arguments F and G.
Year
View sourceYear[n]
DEPRECATED
This function is deprecated and should be avoided. It will be removed soon.
Please use the Year constructor, ^Year
, instead.
Create a period of n
years.
zip
View sourcezip[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]
//output> (: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)
Module: rel:base
View sourceFilePos
View sourceFilePos(x)
^FilePos(y, x)
The data type FilePos
.
The type relation Filepos
checks whether x
is of type FilePos
.
The constructor ^FilePos
maps an integer, y
, to its corresponding FilePos
value, x
.
Parameters
Parameter | Type | Description |
---|---|---|
x | FilePos | FilePos variable. |
y | Integer | The value of the FilePos data type. |
Explanation
The data type FilePos
is defined via a value type declaration, and provides the semantic meaning of a file position to its integer value y
.
Filepos
values are used to identify CSV rows when CSV data is loaded into the RKGS.
For more information on CSV loading, see the CSV data and import guides in the RAI documentation (opens in a new tab).
Examples
A FilePos
value can be created with the constructor ^FilePos
:
def output = ^FilePos[10]
The constructor can also be used to extract the integer value “back out” of the value type.
def fp = ^FilePos[4]
def output(i) = exists(x: ^FilePos(i, x) and fp(x))
The type relation FilePos
can be used to check that a value is of this data type.
def data = { 1; ^FilePos[2]}
def output(x) { data(x) and FilePos(x)}
The relation load_csv
that loads CSV data into the system automatically generates FilePos
values that identify the row of the CSV file.
def config:data = """
item, category
laptop, computer
monitor, peripheral
"""
//FilePos automatically generated
def csv = load_csv[config]
def output = csv
def csv_ic {
subset(csv, (RelName, FilePos, String))
}
FixedDecimal
View sourceFixedDecimal(v)
^FixedDecimal[bits, precision]
^FixedDecimal(bits, precision, v)
Data type of fixed precision numbers with the type relation FixedDecimal
and the constructor ^FixedDecimal
.
bits
is the width of the integer type used to back the fixed decimal,
precision
is the number of decimal places, and v
is the integer
representation of the fixed decimal. v
must fit into a bits
-wide
integer.
The integer representation of a fixed decimal is that number multiplied
by 10 ^ precision
. For example, to represent the number 2.3 with a
precision of 3, we would use 2.3 * (10 ^ 3) = 2300
.
Other constructors like decimal
and parse_decimal
are a simpler
way to construct a FixedDecimal
.
Examples
Construct a 32-bit FixedDecimal
with a precision of 3 decimal places equivalent to 5.5.
def output = rel:base:^FixedDecimal[#32, #3, 5500]
//output> (:rel, :base, :FixedDecimal, #32, #3, 5500)
Attempt to construct a 8-bit FixedDecimal
with a precision of 2 decimal places representing 200.
def output = rel:base:^FixedDecimal[#8, #2, 20000]
//output> {} // produces empty output as 20000 is too large to fit into an 8-bit integer.
Check values are fixed decimals:
with rel:base use ^FixedDecimal, FixedDecimal
def output = FixedDecimal(^FixedDecimal[#8, #1, 1])
//output> () // true
def output = FixedDecimal(^FixedDecimal[#32, #3, 5500])
//output> () // true
def output = FixedDecimal(decimal[#32, #3, 5.5])
//output> () // true
def output = FixedDecimal(parse_decimal[#32, #3, "5.5"])
//output> () // true
def output = FixedDecimal(5.5)
//output> {} // false, the provided value is a Float
See Also
decimal
and parse_decimal
.
UUID
View sourceUUID(x)
^UUID(y, x)
The data type UUID
.
The type relation UUID(x)
checks whether x
is of type UUID
.
The constructor ^UUID(y, x)
maps a UInt128, y
, to its corresponding UUID
value, x
.
Parameters
Parameter | Type | Description |
---|---|---|
x | UUID | UUID variable. |
y | UInt128 | The value of the UUID data type. |
Explanation
UUID
is an efficient representation of UUID values (compared to treating UUIDs as
strings). Compared to a plain UInt128, it provides tools with the information to format
and treat the value as a UUID.
To use rel:base:UUID
or rel:base:^UUID
the full name must be used or abbreviated
as with rel:base use UUID, ^UUID
. The relations UUID
and ^UUID
are not
available as an alias without rel:base
.
Examples
A UUID
value can be created with the constructor ^UUID
with a UInt128
argument:
with rel:base use ^UUID
def output = ^UUID[0x8f9924a8494741e80c464d9df14fe1d0]
//output> (:rel, :base, :UUID, 190874768316354382993454873408336552400)
To create a UUID from a string, use uuid_from_string
:
with rel:base use uuid_from_string
def output = uuid_from_string["184f8380-ba48-494a-9d77-2f410c9aef28"]
//output> (:rel, :base, :UUID, 32314330545176713121947364484890423080)
To format UUID
as a standard UUID string, use string
.
with rel:base use uuid_from_string
def example = uuid_from_string["184f8380-ba48-494a-9d77-2f410c9aef28"]
def output = string[example]
//output> "184f8380-ba48-494a-9d77-2f410c9aef28"
The constructor can be used to extract the integer value “back out” of the value type.
with rel:base use uuid_from_string, ^UUID
def example = uuid_from_string["184f8380-ba48-494a-9d77-2f410c9aef28"]
def output(i) = exists(x: ^UUID(i, x) and example(x))
//output> 32314330545176713121947364484890423080
The type relation UUID
can be used to check that a value is of this data type.
with rel:base use uuid_from_string, UUID
def example = uuid_from_string["184f8380-ba48-494a-9d77-2f410c9aef28"]
def data = 1; example
def output(x) = data(x) and UUID(x)
//output> (:rel, :base, :UUID, 32314330545176713121947364484890423080)
The UUID value type is used by load_csv
for columns with schema "uuid"
:
def config:data = """
A,B
1,b3b8a827-685f-4239-b0b3-afc41dfdc75c
2,6c8440c6-c441-4c75-9d36-1deb97f734ea
3,72327575-620b-4540-b13b-bdfe8e3ea24c
"""
def config:schema:A = "int"
def config:schema:B = "uuid"
def output = load_csv[config]
// output>
// (:A, 2, 1)
// (:A, 3, 2)
// (:A, 4, 3)
// (:B, 2, (:rel, :base, :UUID, 238890604434483702785039736746549299036))
// (:B, 3, (:rel, :base, :UUID, 144243320552226326224531778065386648810))
// (:B, 4, (:rel, :base, :UUID, 151793988704368948489985156409689285196))
JSON export formats UUID values automatically to the standard string representation.
uuid_from_string
View sourceuuid_from_string(s in String, x in UUID)
Parse a UUID string (in the standard 8-4-4-4-12 format) to a UUID value.
Example:
with rel:base use uuid_from_string
def output = uuid_from_string["22b4a8a1-e548-4eeb-9270-60426d66a48e"]
//output> (:rel, :base, :UUID, 46131785562730469527277340045557015694)
SHA1
View sourceSHA1(x)
^SHA1(a in UInt128, b in UInt32, x)
The data type SHA1
.
The type relation SHA1(x)
checks whether x
is of type SHA1
.
The constructor ^SHA1(a, b, x)
maps a UInt128 a
and a UInt32 b
to the SHA1
value x
.
Parameters
Parameter | Type | Description |
---|---|---|
x | SHA1 | SHA1 variable. |
a | UInt128 | The first 128 bits of the 160 bits SHA-1 value. |
b | UInt32 | The last 32 bits of the 160 bits SHA-1 value. |
Explanation
SHA1
is an efficient representation of SHA-1 values (compared to treating SHA-1 as
strings). The value type provides tools with the information to format and treat the
value as a SHA-1 hash.
To use rel:base:SHA1
or rel:base:^SHA1
the full name must be used or abbreviated
as with rel:base use SHA1, ^SHA1
. The relations SHA1
and ^SHA1
are not
available as an alias without rel:base
.
Examples
A SHA1
value can be created with the constructor, though it requires passing in the
two separate parameters. SHA-1 uses 160 bits and Rel does not have 160-bit integer type.
with rel:base use ^SHA1
def output = ^SHA1[0x0d7d4a744fd92effd1ed88e48ac8231e, 0x7f7e9e6c]
//output> (:rel, :base, :SHA1, 17930511166010156306237819770844488478, 2139004524)
To format SHA1
as a standard hexadecimal string, use string
.
with rel:base use ^SHA1
def example = ^SHA1[0x0d7d4a744fd92effd1ed88e48ac8231e, 0x7f7e9e6c]
def output = string[example]
//output> "0d7d4a744fd92effd1ed88e48ac8231e7f7e9e6c"
The type relation SHA1
can be used to check that a value is of this data type.
with rel:base use SHA1, sha1_from_string
def example = sha1_from_string["0d7d4a744fd92effd1ed88e48ac8231e7f7e9e6c"]
def data = 1; example
def output(x) = data(x) and SHA1(x)
//output> (:rel, :base, :SHA1, 17930511166010156306237819770844488478, 2139004524)
The SHA1
value type is used by load_csv
for columns with schema "sha-1"
:
def config:data = """
A,B
1,0d7d4a744fd92effd1ed88e48ac8231e7f7e9e6c
2,10bb3e970ba01ec67439f1764da9ff43b5a7edd5
3,187ca6345d5d759f23d37e5060e023b9888cbbd7
"""
def config:schema:A = "int"
def config:schema:B = "sha-1"
def output = load_csv[config]
//output>
// (:A, 2, 1)
// (:A, 3, 2)
// (:A, 4, 3)
// (:B, 2, (:rel, :base, :SHA1, 17930511166010156306237819770844488478, 2139004524))
// (:B, 3, (:rel, :base, :SHA1, 22239876921550541361475316713022684995, 3047681493))
// (:B, 4, (:rel, :base, :SHA1, 32548687738050047961766682367612691385, 2290924503))
JSON export formats SHA-1 values automatically to the standard string representation.
sha1_from_string
View sourcesha1_from_string(s in String, v in SHA1)
Parse a SHA-1 string (in hexadecimal format) to a SHA1 value.
Example:
with rel:base use sha1_from_string
def output = sha1_from_string["0d7d4a744fd92effd1ed88e48ac8231e7f7e9e6c"]
//output> (:rel, :base, :SHA1, 17930511166010156306237819770844488478, 2139004524)
Date
View sourceDate(d)
^Date(n, d)
The Date
data type representing a date in days of the proleptic Gregorian calendar.
The type relation Date
checks if d
is of type Date
.
The constructor ^Date
creates a date d
of n
days in the
Gregorian calendar starting at 0000-12-31
, which is “day 0”.
Parameters
Parameter | Type | Description |
---|---|---|
d | Date | Date variable. |
n | Integer | The value of the Date data type, in days of the Gregorian calendar. |
Explanation
To use the ^Date(n, d)
constructor, one has to specify all arguments and partial application, ^Date[n]
, can’t be used due to the overloaded nature of the ^Date
constructor.
Examples
Construct a date from the duration in days.
def output(d) = ^Date(734638, d) // 734638 days since 0000-12-31
//output> 2012-05-15
Construct a date from its parts (year, month, day).
^Date[2012, 5, 15]
//output> 2012-05-15
Subtract two date literals. The result is of type Day
.
def output = 2012-06-15 - 2012-05-15
//output> 31
DateTime
View sourceDateTime(dt)
^DateTime(n, dt)
The DateTime
data type representing an instant in milliseconds of the proleptic
Gregorian calendar.
The type relation DateTime
checks if dt
is of type DateTime
.
The constructor ^DateTime
creates an instant d
of n
milliseconds in the
Gregorian calendar, where the reference timestamp 0000-12-31T00:00:00Z
.
Parameters
Parameter | Type | Description |
---|---|---|
dt | DateTime | DateTime variable. |
n | Integer | The value of the DateTime data type, in milliseconds of the Gregorian calendar. |
Explanation
To use the ^DateTime(n, d)
constructor, one has to specify all arguments and partial application, ^DateTime[n]
, can’t be used due to the overloaded nature of the ^DateTime
constructor.
Examples
Construct a datetime from the duration in milliseconds.
def output(dt) = ^DateTime(63472766399000, dt)
//output> 2012-05-15T11:59:59.000Z
Construct a datetime from its parts (year, month, day, hour, minute, second, millisecond, timezone).
^DateTime[2012, 5, 15, 11, 59, 59, 0, "UTC"]
//output> 2012-05-15T11:59:59.000Z
Subtract two datetime literals. The result is of type Millisecond
.
def output = 2012-05-15T00:00:00Z - 2012-05-14T00:00:00Z
//output> 86400000
Year
View sourceYear(p)
^Year(n, p)
A period that spans n
years. The period is given in units of Year
.
The type relation rel:base:Year
checks if p
is of type Year
.
The constructor ^Year
maps the integer n
to the corresponding Year
period p
.
Parameters
Parameter | Type | Description |
---|---|---|
p | Year | A period representing n years. |
n | Integer | The number of the years represented by p . |
Explanation
To use the rel:base:Year(p)
type relation, one must include the rel:base
module name.
Examples
Add 10 years to a datetime.
datetime_add[unix_epoch, ^Year[10]]
//output> 1980-01-01T00:00:00.000Z
Add two Year
periods together.
def output = ^Year[10] + ^Year[2]
//output> 12
Month
View sourceMonth(p)
^Month(n, p)
A period that spans n
months. The period is given in units of Month
.
The type relation rel:base:Month
checks if p
is of type Month
.
The constructor ^Month
maps the integer n
to the corresponding Month
period p
.
Parameters
Parameter | Type | Description |
---|---|---|
p | Month | A period representing n months. |
n | Integer | The number of the months represented by p . |
Explanation
To use the rel:base:Month(p)
type relation, one must include the rel:base
module name.
Examples
Add 10 months to a datetime.
datetime_add[unix_epoch, ^Month[10]]
//output> 1970-11-01T00:00:00.000Z
Add two Month
periods together.
def output = ^Month[10] + ^Month[2]
//output> 12
Week
View sourceWeek(p)
^Week(n, p)
A period that spans n
weeks. The period is given in units of Week
.
The type relation rel:base:Week
checks if p
is of type Week
.
The constructor ^Week
maps the integer n
to the corresponding Week
period p
.
Parameters
Parameter | Type | Description |
---|---|---|
p | Week | A period representing n weeks. |
n | Integer | The number of the weeks represented by p . |
Explanation
To use the rel:base:Week(p)
type relation, one must include the rel:base
module name.
Examples
Add 10 weeks to a datetime.
datetime_add[unix_epoch, ^Week[10]]
//output> 1970-03-12T00:00:00.000Z
Add two Week
periods together.
def output = ^Week[10] + ^Week[2]
//output> 12
Day
View sourceDay(p)
^Day(n, p)
A period that spans n
days. The period is given in units of Day
.
The type relation rel:base:Day
checks if p
is of type Day
.
The constructor ^Day
maps the integer n
to the corresponding Day
period p
.
Parameters
Parameter | Type | Description |
---|---|---|
p | Day | A period representing n days. |
n | Integer | The number of the days represented by p . |
Explanation
To use the rel:base:Day(p)
type relation, one must include the rel:base
module name.
Examples
Add 10 days to a datetime.
datetime_add[unix_epoch, ^Day[10]]
//output> 1970-01-11T00:00:00.000Z
Add two Day
periods together.
def output = ^Day[10] + ^Day[2]
//output> 12
Hour
View sourceHour(p)
^Hour(n, p)
A period that spans n
hours. The period is given in units of Hour
.
The type relation rel:base:Hour
checks if p
is of type Hour
.
The constructor ^Hour
maps the integer n
to the corresponding Hour
period p
.
Parameters
Parameter | Type | Description |
---|---|---|
p | Hour | A period representing n hours. |
n | Integer | The number of the hours represented by p . |
Explanation
To use the rel:base:Hour(p)
type relation, one must include the rel:base
module name.
Examples
Add 10 hours to a datetime.
datetime_add[unix_epoch, ^Hour[10]]
//output> 1970-01-01T10:00:00.000Z
Add two Hour
periods together.
def output = ^Hour[10] + ^Hour[2]
//output> 12
Minute
View sourceMinute(p)
^Minute(n, p)
A period that spans n
minutes. The period is given in units of Minute
.
The type relation rel:base:Minute
checks if p
is of type Minute
.
The constructor ^Minute
maps the integer n
to the corresponding Minute
period p
.
Parameters
Parameter | Type | Description |
---|---|---|
p | Minute | A period representing n minutes. |
n | Integer | The number of the minutes represented by p . |
Explanation
To use the rel:base:Minute(p)
type relation, one must include the rel:base
module name.
Examples
Add 100 minutes to a datetime.
datetime_add[unix_epoch, ^Minute[100]]
//output> 1970-01-01T01:40:00.000Z
Add two Minute
periods together.
def output = ^Minute[10] + ^Minute[2]
//output> 12
Second
View sourceSecond(p)
^Second(n, p)
A period that spans n
seconds. The period is given in units of Second
.
The type relation rel:base:Second
checks if p
is of type Second
.
The constructor ^Second
maps the integer n
to the corresponding Second
period p
.
Parameters
Parameter | Type | Description |
---|---|---|
p | Second | A period representing n seconds. |
n | Integer | The number of the seconds represented by p . |
Explanation
To use the rel:base:Second(p)
type relation, one must include the rel:base
module name.
Examples
Add 100 seconds to a datetime.
datetime_add[unix_epoch, ^Second[100]]
//output> 1970-01-01T00:01:40.000Z
Add two Second
periods together.
def output = ^Second[10] + ^Second[2]
//output> 12
Millisecond
View sourceMillisecond(p)
^Millisecond(n, p)
A period that spans n
milliseconds. The period is given in units of Millisecond
( seconds).
The type relation rel:base:Millisecond
checks if p
is of type Millisecond
.
The constructor ^Millisecond
maps the integer n
to the corresponding Millisecond
period p
.
Parameters
Parameter | Type | Description |
---|---|---|
p | Millisecond | A period representing n milliseconds. |
n | Integer | The number of the milliseconds represented by p . |
Explanation
To use the rel:base:Millisecond(p)
type relation, one must include the rel:base
module name.
Examples
Add 20 thousand milliseconds (aka 20 s) to a datetime.
datetime_add[unix_epoch, ^Millisecond[20 * 10^3]]
//output> 1970-01-01T00:00:20.000Z
Add two Millisecond
periods together.
def output = ^Millisecond[10] + ^Millisecond[2]
//output> 12
Microsecond
View sourceMicrosecond(p)
^Microsecond(n, p)
A period that spans n
microseconds. The period is given in units of Microsecond
( seconds).
The type relation rel:base:Microsecond
checks if p
is of type Microsecond
.
The constructor ^Microsecond
maps the integer n
to the corresponding Microsecond
period p
.
Parameters
Parameter | Type | Description |
---|---|---|
p | Microsecond | A period representing n microseconds. |
n | Integer | The number of the microseconds represented by p . |
Explanation
To use the rel:base:Microsecond(p)
type relation, one must include the rel:base
module name.
Examples
Add 5 million microseconds (aka 5 s) to a datetime.
datetime_add[unix_epoch, ^Microsecond[5 * 10^6]]
//output> 1970-01-01T00:00:05.000Z
Add two Microsecond
periods together.
def output = ^Microsecond[10] + ^Microsecond[2]
//output> 12
Nanosecond
View sourceNanosecond(p)
^Nanosecond(n, p)
A period that spans n
nanoseconds. The period is given in units of Nanosecond
( seconds).
The type relation rel:base:Nanosecond
checks if p
is of type Nanosecond
.
The constructor ^Nanosecond
maps the integer n
to the corresponding Nanosecond
period p
.
Parameters
Parameter | Type | Description |
---|---|---|
p | Nanosecond | A period representing n nanoseconds. |
n | Integer | The number of the nanoseconds represented by p . |
Explanation
To use the rel:base:Nanosecond(p)
type relation, one must include the rel:base
module name.
Examples
Add 20 million nanoseconds (aka 20 ms) to a datetime.
def dt = parse_datetime["2020-01-01 01:00:00.001", "Y-m-d H:M:S.sss"]
def output = dt + ^Nanosecond[20 * 10^6]
//output> 2020-01-01T01:00:00.021.000Z
Add two Nanosecond
periods together.
def output = ^Nanosecond[10] + ^Nanosecond[2]
//output> 12
Module: rel:bignum
View sourceBigInteger
View source Type for arbitrary precision integers.
A Rel representation of the GMP integer type, as in https://gmplib.org/manual/Integer-Internals (opens in a new tab)
The Int8 is a sign (+/- 1) and the String is GMP’s “array of limbs” (a little-endian byte representation of abs(x)):