\def\packagedate{13 December 2024}
\def\packageversion{2.0}
\def\packageshortdate{2024/12/13}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Defines various relational algebra symbols.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Version History
% v1.0    Initial version.
% v2.0    Complete rewrite to support Unicode OpenType fonts and LaTeX3.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\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 \__unicode_engine

    \ifLuaTeX
        \PackageInfo{relalg}{LuaTeX\space engine\space detected}
        \bool_set_true:N \__unicode_engine
    \fi

    \ifXeTeX
        \PackageInfo{relalg}{XeTeX\space engine\space detected}
        \bool_set_true:N \__unicode_engine
    \fi

    \bool_if:NTF \__unicode_engine {
        \RequirePackage[no-math]{fontspec}
        \RequirePackage{unicode-math}

        \setmathfont{latinmodern-math.otf}

        % The various join symbols aren't covered very well by many maths fonts
        % (including Latin Modern Math, annoyingly), so let's Frankenstein them
        % in from fonts that do have them. We need to hack the scale to get roughly
        % proportional looking sizes.
        % Outer joins (left, right, full):
        \setmathfont{STIXTwoMath-Regular.otf}[range={"027D5-"027D7}, Scale=0.875]
        % Inner join: (1.143 = 1 / 0.875)
        \setmathfont{KpMath-Light.otf}[range={"02A1D}, Scale=1.143]
    }{
        \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


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% 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 \__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\__ojoin{\rule[0.11ex]{0.25em}{0.1ex}\llap{\rule[1.41ex]{0.25em}{0.1ex}}}
        \NewDocumentCommand{\RelLeftOuterJoin}{}{\ensuremath{\mathbin{\__ojoin\mkern-6.4mu\Join}}}
        \NewDocumentCommand{\RelRightOuterJoin}{}{\ensuremath{\mathbin{\Join\mkern-6.4mu\__ojoin}}}
        \NewDocumentCommand{\RelFullOuterJoin}{}{\ensuremath{\mathbin{\__ojoin\mkern-6.4mu\Join\mkern-6.4mu\__ojoin}}}
    }
\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.
\NewDocumentCommand{\RelLogicalAnd}{}{\ensuremath{\wedge}}
\let\RelLogAnd\RelLogicalAnd
\let\RelAnd\RelLogicalAnd

\NewDocumentCommand{\RelLogicalOr}{}{\ensuremath{\vee}}
\let\RelLogOr\RelLogicalOr
\let\RelOr\RelLogicalOr

\NewDocumentCommand{\RelLogicalNot}{}{\ensuremath{\neg}}
\let\RelLogNot\RelLogicalNot
\let\RelNot\RelLogicalNot

\endinput
