\def\packagedate{13 February 2025}
\def\packageversion{2.2}
\def\packageshortdate{2025/02/13}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Defines various relational algebra symbols.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Version History
% v1.0 Initial version.
% v2.0 Complete rewrite to support Unicode OpenType fonts and LaTeX3.
% v2.1 Plays nicely with other packages that \setmathfont, and only
% interpolates join symbols if they aren’t in the current font.
% v2.2 Added text versions of logical operators (AND, OR, NOT), and
% "parameters" of the form "<x>". Fixed missing \fi.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\NeedsTeXFormat{LaTeX2e}[2001/06/01]
\ProvidesPackage{relalg}%
[\packageshortdate\space v\packageversion\space Relational algebra notation]
\RequirePackage{amsmath}
\RequirePackage{expl3}
\RequirePackage{iftex}
\ExplSyntaxOn
\bool_new:N \g__ra_unicode_engine
\ifLuaTeX
\PackageInfo{relalg}{LuaTeX\space engine\space detected}
\bool_set_true:N \g__ra_unicode_engine
\fi
\ifXeTeX
\PackageInfo{relalg}{XeTeX\space engine\space detected}
\bool_set_true:N \g__ra_unicode_engine
\fi
\bool_if:NTF \g__ra_unicode_engine {
\RequirePackage[no-math]{fontspec}
\RequirePackage{unicode-math}
% Stolen from unicode-math.sty as the fallback in unicode-math doesn't
% seem to work? Weirdly it seems to work in a bare-bones MWE.
\bool_if:NF \g__um_main_font_defined_bool \__um_load_lm:
% The various join symbols aren't covered very well by many maths fonts
% (including Latin Modern Math, annoyingly), so if necessary let's
% Frankenstein them in from fonts that do have them. We need to hack
% the scale to get roughly proportional looking sizes.
% \iffontchar trick from <https://tex.stackexchange.com/questions/642080/newunicodechar-only-if-undeclared>
% Outer joins (left, right, full):
\iffontchar\font "27D5\relax\else\setmathfont{STIXTwoMath-Regular.otf}[range="027D5, Scale=0.875]\fi
\iffontchar\font "27D6\relax\else\setmathfont{STIXTwoMath-Regular.otf}[range="27D6, Scale=0.875]\fi
\iffontchar\font "27D7\relax\else\setmathfont{STIXTwoMath-Regular.otf}[range="27D7, Scale=0.875]\fi
% \setmathfont{STIXTwoMath-Regular.otf}[range={"027D5-"027D7}, Scale=0.875]
% Inner join: (1.143 = 1 / 0.875)
\iffontchar\font "2A1D\relax\else\setmathfont{KpMath-Light.otf}[range="2A1D, Scale=1.143]\fi
}{
\PackageInfo{relalg}{non-Unicode\space engine\space detected}
\RequirePackage{latexsym} % for \Join
}
\ExplSyntaxOff
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% IDENTIFIERS
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% General identifiers.
\NewDocumentCommand{\RelIdentifier}{m}{\ensuremath{\mathit{#1}}}
% Attribute names.
\let\RelAttribute\RelIdentifier
\let\RelAttr\RelIdentifier
% Relation variable names.
\let\RelVariable\RelIdentifier
\let\RelVar\RelIdentifier
% Attribute sets: \RelAttributeSet{foo,bar,baz}, \RelAttrSet{foo,bar,baz}
% <https://tex.stackexchange.com/a/159132>, expl3 manual Section 23
\ExplSyntaxOn
\NewDocumentCommand{\RelAttributeSet}{m}{
\clist_clear:N \l_tmpa_clist
\clist_map_inline:nn{#1}{
\clist_put_right:Nn \l_tmpa_clist {\RelAttribute{##1}}
}
\ensuremath{\{\clist_use:Nn \l_tmpa_clist {,}\}}
}
\let\RelAttrSet\RelAttributeSet
\ExplSyntaxOff
% "Parameters" of the form "<x>".
\NewDocumentCommand{\RelParameter}{m}{\ensuremath{\langle\RelIdentifier{#1}\rangle}}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% BASIC OPERATORS
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Restrict (select) operator.
\NewDocumentCommand{\RelRestrict}{}{\ensuremath{\sigma}}
\let\RelSelect\RelRestrict
% Project operator.
\NewDocumentCommand{\RelProject}{}{\ensuremath{\pi}}
% Set union operator.
\NewDocumentCommand{\RelUnion}{}{\ensuremath{\cup}}
% Set difference operator.
\NewDocumentCommand{\RelDifference}{}{\ensuremath{-}}
\let\RelMinus\RelDifference
% Cartesian product operator.
\NewDocumentCommand{\RelCartesianProduct}{}{\ensuremath{\times}}
\let\RelProduct\RelCartesianProduct
\let\RelTimes\RelCartesianProduct
% Rename operator.
\NewDocumentCommand{\RelRename}{}{\ensuremath{\rho}}
% Extend operator.
\NewDocumentCommand{\RelExtend}{}{\ensuremath{\epsilon}}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ADDITIONAL OPERATORS
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Set intersection operator.
\NewDocumentCommand{\RelIntersection}{}{\ensuremath{\cap}}
\let\RelIntersect\RelIntersection
% Join operator (including natural join).
% For some reason XeTeX puts less space in front of the operator than LuaTeX.
% Adding +2.5mu for XeTeX looks close enough to LuaTeX's output. This also
% applies to the outer join operators below.
\NewDocumentCommand{\RelJoin}{}{\ensuremath{\ifXeTeX\mkern2.5mu\fi\mathbin{\Join}}}
\let\RelNaturalJoin\RelJoin
\let\RelNatJoin\RelJoin
\let\RelNJoin\RelJoin
% Division operator (two alternatives).
\NewDocumentCommand{\RelDivide}{}{\ensuremath{/}}
\NewDocumentCommand{\RelAltDivide}{}{\ensuremath{\div}}
% Assignment operator.
\NewDocumentCommand{\RelAssign}{}{\ensuremath{\leftarrow}}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% EXTENDED OPERATORS
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Aggregate functions.
\DeclareMathOperator{\AggAvg}{avg}
\DeclareMathOperator{\AggCount}{count}
\DeclareMathOperator{\AggMin}{min}
\DeclareMathOperator{\AggMax}{max}
\DeclareMathOperator{\AggSum}{sum}
\NewDocumentCommand{\RelAggregrate}{m m}{\ensuremath{\mathcal{G}_{#1}(#2)}}
\NewDocumentCommand{\RelAverage}{m}{\RelAggregrate{\AggAverage}{#1}}
\let\RelAvg\RelAverage
\NewDocumentCommand{\RelCount}{m}{\RelAggregrate{\AggCount}{#1}}
\NewDocumentCommand{\RelMaximum}{m}{\RelAggregrate{\AggMax}{#1}}
\let\RelMax\RelMaximum
\NewDocumentCommand{\RelMinimum}{m}{\RelAggregrate{\AggMin}{#1}}
\let\RelMin\RelMinimum
\NewDocumentCommand{\RelSum}{m}{\RelAggregrate{\AggSum}{#1}}
% Outer join operators.
\ExplSyntaxOn
\bool_if:NTF \g__ra_unicode_engine {
\NewDocumentCommand{\RelLeftOuterJoin}{}{\ensuremath{\ifXeTeX\mkern2.5mu\fi\mathbin{\leftouterjoin}}}
\NewDocumentCommand{\RelRightOuterJoin}{}{\ensuremath{\ifXeTeX\mkern2.5mu\fi\mathbin{\rightouterjoin}}}
\NewDocumentCommand{\RelFullOuterJoin}{}{\ensuremath{\ifXeTeX\mkern2.5mu\fi\mathbin{\fullouterjoin}}}
}{
% Hand-tweaked for non-Unicode engines based on answers at
% <https://tex.stackexchange.com/questions/20740/symbols-for-outer-joins>
% Weirdly the height of \Join is fractionally shorter than \bowtie, so
% we can't use the more sensible solution of measuring off the line
% height. Use only font-relative units to ensure proper scaling.
\def\__ra_outer_join{\rule[0.11ex]{0.25em}{0.1ex}\llap{\rule[1.41ex]{0.25em}{0.1ex}}}
\NewDocumentCommand{\RelLeftOuterJoin}{}{\ensuremath{\mathbin{\__ra_outer_join\mkern-6.4mu\Join}}}
\NewDocumentCommand{\RelRightOuterJoin}{}{\ensuremath{\mathbin{\Join\mkern-6.4mu\__ra_outer_join}}}
\NewDocumentCommand{\RelFullOuterJoin}{}{\ensuremath{\mathbin{\__ra_outer_join\mkern-6.4mu\Join\mkern-6.4mu\__ra_outer_join}}}
}
\ExplSyntaxOff
\let\RelLOuterJoin\RelLeftOuterJoin
\let\RelLeftOuter\RelLeftOuterJoin
\let\RelLOJ\RelLeftOuterJoin
\let\RelROuterJoin\RelRightOuterJoin
\let\RelRightOuter\RelRightOuterJoin
\let\RelROJ\RelRightOuterJoin
\let\RelFOuterJoin\RelFullOuterJoin
\let\RelFullOuter\RelFullOuterJoin
\let\RelFOJ\RelFullOuterJoin
% Semijoin operator.
\NewDocumentCommand{\RelLeftSemiJoin}{}{\ensuremath{\ltimes}}
\let\RelSemiJoin\RelLeftSemiJoin
\NewDocumentCommand{\RelRightSemiJoin}{}{\ensuremath{\rtimes}}
\let\RelReverseSemiJoin\RelRightSemiJoin
% Antijoin operator.
\NewDocumentCommand{\RelLeftAntiJoin}{}{\ensuremath{\triangleright}}
\let\RelAntiJoin\RelLeftAntiJoin
\NewDocumentCommand{\RelRightAntiJoin}{}{\ensuremath{\triangleleft}}
\let\RelReverseAntiJoin\RelRightAntiJoin
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% MISCELLANEOUS
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Logical operators.
\DeclareMathOperator{\AndText}{AND}
\DeclareMathOperator{\OrText}{OR}
\DeclareMathOperator{\NotText}{NOT}
\ExplSyntaxOn
\NewDocumentCommand{\RelLogicalAnd}{O{symbol}}{
\tl_if_eq:nnTF {#1} {text}
{\ensuremath{\AndText}}
{\ensuremath{\wedge}}
}
\let\RelLogAnd\RelLogicalAnd
\let\RelAnd\RelLogicalAnd
\NewDocumentCommand{\RelLogicalOr}{O{symbol}}{
\tl_if_eq:nnTF {#1} {text}
{\ensuremath{\OrText}}
{\ensuremath{\vee}}
}
\let\RelLogOr\RelLogicalOr
\let\RelOr\RelLogicalOr
\NewDocumentCommand{\RelLogicalNot}{O{symbol}}{
\tl_if_eq:nnTF {#1} {text}
{\ensuremath{\NotText}}
{\ensuremath{\neg}}
}
\let\RelLogNot\RelLogicalNot
\let\RelNot\RelLogicalNot
\ExplSyntaxOff
\endinput