diff --git a/relalg.sty b/relalg.sty index b2626df..8941b1a 100644 --- a/relalg.sty +++ b/relalg.sty @@ -1,16 +1,91 @@ +\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}[2008/02/28 Relational algebra notation] +\ProvidesPackage{relalg}% + [\packageshortdate\space v\packageversion\space Relational algebra notation] -\RequirePackage{amssymb} -\RequirePackage{latexsym} -\RequirePackage{graphics} -% Graphics is needed so that we can scale the size of a couple of operators. + +\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} +% , 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 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -19,34 +94,30 @@ % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% select or restrict operator -\newcommand{\RelSelect}{\ensuremath{\sigma}} -\newcommand{\RelRestrict}{\RelSelect} +% Restrict (select) operator. +\NewDocumentCommand{\RelRestrict}{}{\ensuremath{\sigma}} +\let\RelSelect\RelRestrict -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% project operator -\newcommand{\RelProject}{\ensuremath{\pi}} +% Project operator. +\NewDocumentCommand{\RelProject}{}{\ensuremath{\pi}} -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% set union operator -\newcommand{\RelUnion}{\ensuremath{\cup}} +% Set union operator. +\NewDocumentCommand{\RelUnion}{}{\ensuremath{\cup}} -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% set difference operator -\newcommand{\RelDifference}{\ensuremath{-}} +% Set difference operator. +\NewDocumentCommand{\RelDifference}{}{\ensuremath{-}} +\let\RelMinus\RelDifference -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% cartesian product operator -\newcommand{\RelProduct}{\ensuremath{\times}} +% Cartesian product operator. +\NewDocumentCommand{\RelCartesianProduct}{}{\ensuremath{\times}} +\let\RelProduct\RelCartesianProduct +\let\RelTimes\RelCartesianProduct -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% rename operator -\newcommand{\RelRename}{\ensuremath{\rho}} +% Rename operator. +\NewDocumentCommand{\RelRename}{}{\ensuremath{\rho}} -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% extend operator -\newcommand{\RelExtend}{\ensuremath{\epsilon}} +% Extend operator. +\NewDocumentCommand{\RelExtend}{}{\ensuremath{\epsilon}} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -55,25 +126,25 @@ % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% set intersection operator -\newcommand{\RelIntersection}{\ensuremath{\cap}} -\newcommand{\RelIntersect}{\RelIntersection} +% Set intersection operator. +\NewDocumentCommand{\RelIntersection}{}{\ensuremath{\cap}} +\let\RelIntersect\RelIntersection -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% natural join operator -\newcommand{\RelNaturalJoin}{\ensuremath{\Join}} -\newcommand{\RelNatJoin}{\RelNatJoin} -\newcommand{\RelNJoin}{\RelNJoin} +% 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 operators -\newcommand{\RelDivide}{\ensuremath{/}} -\newcommand{\RelAltDivide}{\ensuremath{\div}} +% Division operator (two alternatives). +\NewDocumentCommand{\RelDivide}{}{\ensuremath{/}} +\NewDocumentCommand{\RelAltDivide}{}{\ensuremath{\div}} -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% assignment operator -\newcommand{\RelAssign}{\ensuremath{\leftarrow}} +% Assignment operator. +\NewDocumentCommand{\RelAssign}{}{\ensuremath{\leftarrow}} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -82,44 +153,72 @@ % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% aggregate functions -\newcommand{\RelAggregrate}[2]{\ensuremath{\mathcal{G}_{\mathbf{\mathrm{#1}}(#2)}}} -\newcommand{\RelSum}[1]{\RelAggregrate{sum}{#1}} -\newcommand{\RelAvg}[1]{\RelAggregrate{avg}{#1}} -\newcommand{\RelMin}[1]{\RelAggregrate{min}{#1}} -\newcommand{\RelMax}[1]{\RelAggregrate{max}{#1}} -\newcommand{\RelCount}[1]{\RelAggregrate{count}{#1}} +% Aggregate functions. +\DeclareMathOperator{\AggAvg}{avg} +\DeclareMathOperator{\AggCount}{count} +\DeclareMathOperator{\AggMin}{min} +\DeclareMathOperator{\AggMax}{max} +\DeclareMathOperator{\AggSum}{sum} -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% outer join operators -% Note: can't use \ensuremath in these because it screws up the spacing. -% The $ are OK though because they're used inside hboxes anyway. -\newcommand{\RelLeftOuterJoin}{\scalebox{0.5}[1]{$\sqsupset$}\mkern-2.5mu\lower0.1em\hbox{$\Join$}} -\newcommand{\RelleftOuterJoin}{\RelLeftOuterJoin} -\newcommand{\RelLOuterJoin}{\RelLeftOuterJoin} -\newcommand{\RelLeftOuter}{\RelLeftOuterJoin} -\newcommand{\RelLOJ}{\RelLeftOuterJoin} +\NewDocumentCommand{\RelAggregrate}{m m}{\ensuremath{\mathcal{G}_{#1}(#2)}} -\newcommand{\RelRightOuterJoin}{\lower0.1em\hbox{$\Join$}\mkern-2.5mu\scalebox{0.5}[1]{$\sqsubset$}} -\newcommand{\RelrightOuterJoin}{\RelRightOuterJoin} -\newcommand{\RelROuterJoin}{\RelRightOuterJoin} -\newcommand{\RelRightOuter}{\RelRightOuterJoin} -\newcommand{\RelROJ}{\RelRightOuterJoin} +\NewDocumentCommand{\RelAverage}{m}{\RelAggregrate{\AggAverage}{#1}} +\let\RelAvg\RelAverage -\newcommand{\RelFullOuterJoin}{\scalebox{0.5}[1]{$\sqsupset$}\mkern-2.5mu\lower0.1em\hbox{$\Join$}\mkern-2.5mu\scalebox{0.5}[1]{$\sqsubset$}} -\newcommand{\RelfullOuterJoin}{\RelFullOuterJoin} -\newcommand{\RelFOuterJoin}{\RelFullOuterJoin} -\newcommand{\RelFullOuter}{\RelFullOuterJoin} -\newcommand{\RelFOJ}{\RelFullOuterJoin} +\NewDocumentCommand{\RelCount}{m}{\RelAggregrate{\AggCount}{#1}} -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% semijoin operator -\newcommand{\RelSemiJoin}{\ensuremath{\ltimes}} +\NewDocumentCommand{\RelMaximum}{m}{\RelAggregrate{\AggMax}{#1}} +\let\RelMax\RelMaximum -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% antijoin operator -\newcommand{\RelAntiJoin}{\ensuremath{\triangleright}} +\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 + % + % 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 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -128,16 +227,17 @@ % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% logical operators -% \And appears to conflict with beamer? (unconfirmed) -\newcommand{\RelLogicalAnd}{\ensuremath{\wedge}} -\newcommand{\RelLogAnd}{\RelLogicalAnd} +% Logical operators. +\NewDocumentCommand{\RelLogicalAnd}{}{\ensuremath{\wedge}} +\let\RelLogAnd\RelLogicalAnd +\let\RelAnd\RelLogicalAnd -\newcommand{\RelLogicalOr}{\ensuremath{\vee}} -\newcommand{\RelLogOr}{\RelLogicalOr} +\NewDocumentCommand{\RelLogicalOr}{}{\ensuremath{\vee}} +\let\RelLogOr\RelLogicalOr +\let\RelOr\RelLogicalOr -\newcommand{\RelLogicalNot}{\ensuremath{\neg}} -\newcommand{\RelLogNot}{\RelLogicalNot} +\NewDocumentCommand{\RelLogicalNot}{}{\ensuremath{\neg}} +\let\RelLogNot\RelLogicalNot +\let\RelNot\RelLogicalNot \endinput