vector/table: Add comparison operators
commit
8e7a946127
|
@ -33,7 +33,7 @@
|
|||
<import package="vector/fold" />
|
||||
<import package="vector/interpolate" />
|
||||
<import package="vector/length" />
|
||||
<import package="vector/stub" />
|
||||
<import package="vector/table" />
|
||||
|
||||
<import package="aggregate" />
|
||||
<import package="insurance" />
|
||||
|
|
|
@ -130,9 +130,9 @@
|
|||
<rate yields="interpTableMaxFieldValue">
|
||||
<t:query-first-field table="interp-query-field-test"
|
||||
field="value">
|
||||
<t:when field="key">
|
||||
<t:where-eq field="key">
|
||||
<c:value-of name="interpTableMaxKeyValue" />
|
||||
</t:when>
|
||||
</t:where-eq>
|
||||
</t:query-first-field>
|
||||
</rate>
|
||||
</section>
|
||||
|
@ -170,10 +170,10 @@
|
|||
key="key"
|
||||
step="INTERP_TABLE_STEP"
|
||||
actual="#300">
|
||||
<t:when field="pred">
|
||||
<t:where-eq field="pred">
|
||||
<c:const value="31" type="float"
|
||||
desc="Test predicate value" />
|
||||
</t:when>
|
||||
</t:where-eq>
|
||||
</t:interpolate-query-field>
|
||||
</t:given>
|
||||
|
||||
|
@ -220,10 +220,10 @@
|
|||
key="key"
|
||||
step="INTERP_TABLE_STEP"
|
||||
actual="#350">
|
||||
<t:when field="pred">
|
||||
<t:where-eq field="pred">
|
||||
<c:const value="31" type="float"
|
||||
desc="Test predicate value" />
|
||||
</t:when>
|
||||
</t:where-eq>
|
||||
</t:interpolate-query-field>
|
||||
</t:given>
|
||||
|
||||
|
|
|
@ -0,0 +1,382 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Copyright (C) 2018 R-T Specialty, LLC.
|
||||
|
||||
This file is part of tame-core.
|
||||
|
||||
tame-core is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<package xmlns="http://www.lovullo.com/rater"
|
||||
xmlns:c="http://www.lovullo.com/calc"
|
||||
xmlns:t="http://www.lovullo.com/rater/apply-template"
|
||||
desc="Table Querying Specs">
|
||||
|
||||
<import package="../../spec" />
|
||||
|
||||
<import package="../../../base" />
|
||||
<import package="../../../vector/table" />
|
||||
|
||||
|
||||
<t:create-table name="test-table"
|
||||
desc="Dummy table for query testing">
|
||||
<t:table-column name="a"
|
||||
index="0"
|
||||
desc="Column A" />
|
||||
<t:table-column name="b"
|
||||
index="1"
|
||||
desc="Column B" />
|
||||
<t:table-column name="c"
|
||||
index="2"
|
||||
desc="Column C" />
|
||||
|
||||
<t:table-rows>
|
||||
<t:table-row>
|
||||
<t:table-value const="1" />
|
||||
<t:table-value const="11" />
|
||||
<t:table-value const="111" />
|
||||
</t:table-row>
|
||||
<t:table-row>
|
||||
<t:table-value const="1" />
|
||||
<t:table-value const="12" />
|
||||
<t:table-value const="121" />
|
||||
</t:table-row>
|
||||
|
||||
<t:table-row>
|
||||
<t:table-value const="2" />
|
||||
<t:table-value const="21" />
|
||||
<t:table-value const="111" />
|
||||
</t:table-row>
|
||||
</t:table-rows>
|
||||
</t:create-table>
|
||||
|
||||
|
||||
<t:create-table name="test-table-seq"
|
||||
desc="Dummy sequential table for query testing">
|
||||
<t:table-column name="a"
|
||||
index="0"
|
||||
desc="Column A" />
|
||||
<t:table-column name="b"
|
||||
index="1"
|
||||
desc="Column B" />
|
||||
|
||||
<t:table-rows>
|
||||
<t:table-row>
|
||||
<t:table-value const="1" />
|
||||
<t:table-value const="1" />
|
||||
</t:table-row>
|
||||
|
||||
<t:table-row>
|
||||
<t:table-value const="2" />
|
||||
<t:table-value const="1" />
|
||||
</t:table-row>
|
||||
<t:table-row>
|
||||
<t:table-value const="2" />
|
||||
<t:table-value const="2" />
|
||||
</t:table-row>
|
||||
|
||||
<t:table-row>
|
||||
<t:table-value const="5" />
|
||||
<t:table-value const="1" />
|
||||
</t:table-row>
|
||||
<t:table-row>
|
||||
<t:table-value const="5" />
|
||||
<t:table-value const="2" />
|
||||
</t:table-row>
|
||||
<t:table-row>
|
||||
<t:table-value const="5" />
|
||||
<t:table-value const="3" />
|
||||
</t:table-row>
|
||||
|
||||
<t:table-row>
|
||||
<t:table-value const="7" />
|
||||
<t:table-value const="1" />
|
||||
</t:table-row>
|
||||
<t:table-row>
|
||||
<t:table-value const="7" />
|
||||
<t:table-value const="2" />
|
||||
</t:table-row>
|
||||
<t:table-row>
|
||||
<t:table-value const="7" />
|
||||
<t:table-value const="3" />
|
||||
</t:table-row>
|
||||
<t:table-row>
|
||||
<t:table-value const="7" />
|
||||
<t:table-value const="4" />
|
||||
</t:table-row>
|
||||
</t:table-rows>
|
||||
</t:create-table>
|
||||
|
||||
|
||||
<t:describe name="_query-first-field_">
|
||||
<t:it desc="returns first row of multi-row result">
|
||||
<t:given>
|
||||
<t:query-first-field table="test-table" field="c">
|
||||
<t:where-eq field="a">
|
||||
<c:value-of name="#1" />
|
||||
</t:where-eq>
|
||||
</t:query-first-field>
|
||||
</t:given>
|
||||
|
||||
<t:expect>
|
||||
<t:match-result eq="111" />
|
||||
</t:expect>
|
||||
</t:it>
|
||||
|
||||
|
||||
<t:it desc="returns first row of single-row result">
|
||||
<t:given>
|
||||
<t:query-first-field table="test-table" field="c">
|
||||
<t:where-eq field="a">
|
||||
<c:value-of name="#1" />
|
||||
</t:where-eq>
|
||||
<t:where-eq field="b">
|
||||
<c:value-of name="#12" />
|
||||
</t:where-eq>
|
||||
</t:query-first-field>
|
||||
</t:given>
|
||||
|
||||
<t:expect>
|
||||
<t:match-result eq="121" />
|
||||
</t:expect>
|
||||
</t:it>
|
||||
</t:describe>
|
||||
|
||||
|
||||
|
||||
<t:describe name="_query-field_">
|
||||
<t:describe name="with predicates">
|
||||
<t:it desc="returns vector of field values">
|
||||
<t:given>
|
||||
<c:length-of>
|
||||
<t:query-field table="test-table" field="c">
|
||||
<t:where-eq field="a">
|
||||
<c:value-of name="#1" />
|
||||
</t:where-eq>
|
||||
</t:query-field>
|
||||
</c:length-of>
|
||||
</t:given>
|
||||
|
||||
<t:expect>
|
||||
<t:match-result eq="2" />
|
||||
</t:expect>
|
||||
</t:it>
|
||||
|
||||
|
||||
<t:it desc="returns vector of field values even for single result">
|
||||
<t:given>
|
||||
<c:car>
|
||||
<t:query-field table="test-table" field="c">
|
||||
<t:where-eq field="a">
|
||||
<c:value-of name="#1" />
|
||||
</t:where-eq>
|
||||
<t:where-eq field="b">
|
||||
<c:value-of name="#11" />
|
||||
</t:where-eq>
|
||||
</t:query-field>
|
||||
</c:car>
|
||||
</t:given>
|
||||
|
||||
<t:expect>
|
||||
<t:match-result eq="111" />
|
||||
</t:expect>
|
||||
</t:it>
|
||||
</t:describe>
|
||||
|
||||
|
||||
<t:describe name="with no predicates">
|
||||
<t:it desc="returns vector of all field values">
|
||||
<t:given>
|
||||
<c:length-of>
|
||||
<t:query-field table="test-table" field="c" />
|
||||
</c:length-of>
|
||||
</t:given>
|
||||
|
||||
<t:expect>
|
||||
<t:match-result eq="3" />
|
||||
</t:expect>
|
||||
</t:it>
|
||||
</t:describe>
|
||||
|
||||
|
||||
<!-- TODO: tried using inline-template here but id generation was not
|
||||
working as expected -->
|
||||
<t:describe name="with CMP_OP_LT">
|
||||
<t:it desc="matches less than a given value">
|
||||
<t:given>
|
||||
<c:let>
|
||||
<c:values>
|
||||
<c:value name="results" type="integer" set="vector">
|
||||
<t:query-field table="test-table-seq" field="a">
|
||||
<t:where-lt field="a">
|
||||
<c:value-of name="#5" />
|
||||
</t:where-lt>
|
||||
</t:query-field>
|
||||
</c:value>
|
||||
</c:values>
|
||||
|
||||
<c:sum of="results" />
|
||||
</c:let>
|
||||
</t:given>
|
||||
|
||||
<t:expect>
|
||||
<!-- 1 + 2 + 2 -->
|
||||
<t:match-result eq="5" />
|
||||
</t:expect>
|
||||
</t:it>
|
||||
</t:describe>
|
||||
|
||||
|
||||
<t:describe name="with CMP_OP_LTE">
|
||||
<t:it desc="matches less than or equal to a given value">
|
||||
<t:given>
|
||||
<c:let>
|
||||
<c:values>
|
||||
<c:value name="results" type="integer" set="vector">
|
||||
<t:query-field table="test-table-seq" field="a">
|
||||
<t:where-lte field="a">
|
||||
<c:value-of name="#5" />
|
||||
</t:where-lte>
|
||||
</t:query-field>
|
||||
</c:value>
|
||||
</c:values>
|
||||
|
||||
<c:sum of="results" />
|
||||
</c:let>
|
||||
</t:given>
|
||||
|
||||
<t:expect>
|
||||
<!-- 1 + 2 + 2 + 5 + 5 + 5 -->
|
||||
<t:match-result eq="20" />
|
||||
</t:expect>
|
||||
</t:it>
|
||||
</t:describe>
|
||||
|
||||
|
||||
<t:describe name="with CMP_OP_GT">
|
||||
<t:it desc="matches greater than a given value">
|
||||
<t:given>
|
||||
<c:let>
|
||||
<c:values>
|
||||
<c:value name="results" type="integer" set="vector">
|
||||
<t:query-field table="test-table-seq" field="a">
|
||||
<t:where-gt field="a">
|
||||
<c:value-of name="#5" />
|
||||
</t:where-gt>
|
||||
</t:query-field>
|
||||
</c:value>
|
||||
</c:values>
|
||||
|
||||
<c:sum of="results" />
|
||||
</c:let>
|
||||
</t:given>
|
||||
|
||||
<t:expect>
|
||||
<!-- 7 + 7 + 7 + 7 -->
|
||||
<t:match-result eq="28" />
|
||||
</t:expect>
|
||||
</t:it>
|
||||
</t:describe>
|
||||
|
||||
|
||||
<t:describe name="with CMP_OP_GTE">
|
||||
<t:it desc="matches greater than or equal to a given value">
|
||||
<t:given>
|
||||
<c:let>
|
||||
<c:values>
|
||||
<c:value name="results" type="integer" set="vector">
|
||||
<t:query-field table="test-table-seq" field="a">
|
||||
<t:where-gte field="a">
|
||||
<c:value-of name="#5" />
|
||||
</t:where-gte>
|
||||
</t:query-field>
|
||||
</c:value>
|
||||
</c:values>
|
||||
|
||||
<c:sum of="results" />
|
||||
</c:let>
|
||||
</t:given>
|
||||
|
||||
<t:expect>
|
||||
<!-- 5 + 5 + 5 + 7 + 7 + 7 + 7 -->
|
||||
<t:match-result eq="43" />
|
||||
</t:expect>
|
||||
</t:it>
|
||||
</t:describe>
|
||||
</t:describe>
|
||||
|
||||
|
||||
|
||||
<t:describe name="_query-row_">
|
||||
<t:describe name="with predicates">
|
||||
<t:it desc="returns vector of rows">
|
||||
<t:given>
|
||||
<c:length-of>
|
||||
<t:query-row table="test-table">
|
||||
<t:where-eq field="a">
|
||||
<c:value-of name="#1" />
|
||||
</t:where-eq>
|
||||
</t:query-row>
|
||||
</c:length-of>
|
||||
</t:given>
|
||||
|
||||
<t:expect>
|
||||
<t:match-result eq="2" />
|
||||
</t:expect>
|
||||
</t:it>
|
||||
|
||||
|
||||
<t:it desc="returns vector of rows even for single result">
|
||||
<t:given>
|
||||
<c:let>
|
||||
<c:values>
|
||||
<c:value name="first_row" type="integer" set="vector">
|
||||
<c:car>
|
||||
<t:query-row table="test-table">
|
||||
<t:where-eq field="a">
|
||||
<c:value-of name="#1" />
|
||||
</t:where-eq>
|
||||
<t:where-eq field="b">
|
||||
<c:value-of name="#11" />
|
||||
</t:where-eq>
|
||||
</t:query-row>
|
||||
</c:car>
|
||||
</c:value>
|
||||
</c:values>
|
||||
|
||||
<c:sum of="first_row" />
|
||||
</c:let>
|
||||
</t:given>
|
||||
|
||||
<t:expect>
|
||||
<t:match-result eq="123" />
|
||||
</t:expect>
|
||||
</t:it>
|
||||
</t:describe>
|
||||
|
||||
|
||||
<t:describe name="with no predicates">
|
||||
<t:it desc="returns vector of all rows">
|
||||
<t:given>
|
||||
<c:length-of>
|
||||
<t:query-row table="test-table" />
|
||||
</c:length-of>
|
||||
</t:given>
|
||||
|
||||
<t:expect>
|
||||
<t:match-result eq="3" />
|
||||
</t:expect>
|
||||
</t:it>
|
||||
</t:describe>
|
||||
</t:describe>
|
||||
</package>
|
|
@ -24,9 +24,23 @@
|
|||
desc="Filtering Vectors and Matrices">
|
||||
|
||||
<import package="../base" />
|
||||
<import package="../when" />
|
||||
<import package="list" />
|
||||
|
||||
|
||||
<typedef name="CmpOp"
|
||||
desc="Comparison operator">
|
||||
<enum type="integer">
|
||||
<!-- DO NOT REORDER; see mrange 'over' check -->
|
||||
<item name="CMP_OP_EQ" value="1" desc="Equal (=)" />
|
||||
<item name="CMP_OP_LT" value="2" desc="Less than (<)" />
|
||||
<item name="CMP_OP_LTE" value="3" desc="Less than or equal to (<=)" />
|
||||
<item name="CMP_OP_GT" value="4" desc="Greater than (>)" />
|
||||
<item name="CMP_OP_GTE" value="5" desc="Greater than or equal to (>=)" />
|
||||
</enum>
|
||||
</typedef>
|
||||
|
||||
|
||||
<section title="Vector Filtering">
|
||||
<function name="vfilter_lookup"
|
||||
desc="Filter predicate by value and use corresponding index in
|
||||
|
@ -45,10 +59,11 @@
|
|||
|
||||
<section title="Matrix Filtering">
|
||||
\ref{mfilter} handles complex filtering of matrices.
|
||||
If the requested column~\tt{@col@} is marked as sequential with~\tt{@seq@},
|
||||
a~$O(lg n)$ bisect algorithm will be used;
|
||||
otherwise,
|
||||
it will undergo a~$O(n)$ linear scan.
|
||||
If the requested column~\tt{@col@} is marked as sequential with~\tt{@seq@}
|
||||
\emph{and} the comparison operator is~\ref{CMP_OP_EQ},
|
||||
then an~$O(lg n)$ bisect algorithm will be used;
|
||||
otherwise,
|
||||
it will undergo a~$O(n)$ linear scan.
|
||||
|
||||
<function name="mfilter"
|
||||
desc="Filter matrix rows by column value">
|
||||
|
@ -56,6 +71,7 @@
|
|||
<param name="col" type="integer" desc="Column index to filter on" />
|
||||
<param name="vals" type="float" desc="Column value to filter on" />
|
||||
<param name="seq" type="boolean" desc="Is data sequential?" />
|
||||
<param name="op" type="integer" desc="Comparison operator" />
|
||||
|
||||
<!-- merge the result of each condition in vals into a single set, which
|
||||
has the effect of supporting multiple conditions on a single column of
|
||||
|
@ -63,18 +79,16 @@
|
|||
the lookups separately for each, we preserve the bisect-ability of the
|
||||
condition. -->
|
||||
<t:merge-until-empty set="vals" car="val" glance="TABLE_WHEN_MASK_VALUE">
|
||||
<c:apply name="mrange" matrix="matrix" col="col" val="val" seq="seq">
|
||||
<c:apply name="mrange" matrix="matrix" col="col" val="val" seq="seq" op="op">
|
||||
<c:arg name="start">
|
||||
<c:cases>
|
||||
<!-- if we know that the data is sequential, then we may not need to
|
||||
perform a linear search (if the dataset is large enough and the
|
||||
column value is relatively distinct) -->
|
||||
<!-- TODO: bisect is currently only performed for CMP_OP_EQ -->
|
||||
<c:case>
|
||||
<c:when name="seq">
|
||||
<c:eq>
|
||||
<c:value-of name="TRUE" />
|
||||
</c:eq>
|
||||
</c:when>
|
||||
<t:when-eq name="op" value="CMP_OP_EQ" />
|
||||
<t:when-eq name="seq" value="TRUE" />
|
||||
|
||||
<c:apply name="bisect" matrix="matrix" col="col" val="val">
|
||||
<c:arg name="start">
|
||||
|
@ -120,6 +134,7 @@
|
|||
<param name="start" type="integer" desc="Starting index (inclusive)" />
|
||||
<param name="end" type="integer" desc="Ending index (inclusive)" />
|
||||
<param name="seq" type="boolean" desc="Is data sequential?" />
|
||||
<param name="op" type="integer" desc="Comparison operator" />
|
||||
|
||||
<c:let>
|
||||
<c:values>
|
||||
|
@ -145,17 +160,8 @@
|
|||
<c:value name="over" type="boolean"
|
||||
desc="Did we pass the potential value in a sorted list?">
|
||||
<c:value-of name="TRUE">
|
||||
<c:when name="seq">
|
||||
<c:eq>
|
||||
<c:value-of name="TRUE" />
|
||||
</c:eq>
|
||||
</c:when>
|
||||
|
||||
<c:when name="curval">
|
||||
<c:gt>
|
||||
<c:value-of name="val" />
|
||||
</c:gt>
|
||||
</c:when>
|
||||
<t:when-eq name="seq" value="TRUE" />
|
||||
<t:when-gt name="curval" value="val" />
|
||||
</c:value-of>
|
||||
</c:value>
|
||||
</c:values>
|
||||
|
@ -163,33 +169,25 @@
|
|||
<c:cases>
|
||||
<!-- if we're done filtering, then return an empty set -->
|
||||
<c:case>
|
||||
<c:when name="start">
|
||||
<c:gt>
|
||||
<c:value-of name="end" />
|
||||
</c:gt>
|
||||
</c:when>
|
||||
<t:when-gt name="start" value="end" />
|
||||
|
||||
<!-- empty set -->
|
||||
<c:vector />
|
||||
</c:case>
|
||||
|
||||
<!-- if the data is sequential and the next element is over the
|
||||
requested value, then we're done -->
|
||||
requested value, then we're done (can only be used for
|
||||
equality and LT{,E}; need a GT{,E} version -->
|
||||
<c:case>
|
||||
<c:when name="over">
|
||||
<c:eq>
|
||||
<c:value-of name="TRUE" />
|
||||
</c:eq>
|
||||
</c:when>
|
||||
<t:when-lte name="op" value="CMP_OP_LTE" />
|
||||
<t:when-eq name="over" value="TRUE" />
|
||||
|
||||
<!-- empty set -->
|
||||
<c:vector />
|
||||
</c:case>
|
||||
|
||||
|
||||
<c:otherwise>
|
||||
<c:apply name="_mfilter" matrix="matrix" col="col" val="val"
|
||||
start="start" end="end" seq="seq">
|
||||
<c:apply name="_mrange_cmp" matrix="matrix" col="col" val="val"
|
||||
start="start" end="end" seq="seq" op="op">
|
||||
<c:arg name="cur">
|
||||
<c:value-of name="matrix">
|
||||
<!-- current row -->
|
||||
|
@ -211,33 +209,95 @@
|
|||
</function>
|
||||
|
||||
|
||||
<function name="_mfilter" desc="mfilter helper">
|
||||
<!-- mutually recursive with _mrange -->
|
||||
<function name="_mrange_cmp" desc="mrange helper for value comparison">
|
||||
<param name="matrix" type="float" set="matrix" desc="Matrix to filter" />
|
||||
<param name="col" type="integer" desc="Column index to filter on" />
|
||||
<param name="val" type="float" desc="Column value to filter on" />
|
||||
<param name="start" type="integer" desc="Starting index (aka current index)" />
|
||||
<param name="end" type="integer" desc="Ending index" />
|
||||
<param name="seq" type="integer" desc="Is data sequential?" />
|
||||
|
||||
<param name="op" type="integer" desc="Comparison operator" />
|
||||
<param name="cur" type="float" desc="Current value" />
|
||||
|
||||
<c:cases>
|
||||
<c:case>
|
||||
<c:when name="cur">
|
||||
<c:eq>
|
||||
<c:value-of name="val" />
|
||||
</c:eq>
|
||||
</c:when>
|
||||
|
||||
<c:cons>
|
||||
<c:value-of name="matrix">
|
||||
<c:index>
|
||||
<c:value-of name="start" />
|
||||
</c:index>
|
||||
</c:value-of>
|
||||
<c:let>
|
||||
<c:values>
|
||||
<c:value name="found" type="boolean"
|
||||
desc="Whether comparison matches">
|
||||
<c:cases>
|
||||
<c:case label="Equal">
|
||||
<t:when-eq name="op" value="CMP_OP_EQ" />
|
||||
|
||||
<c:value-of name="TRUE">
|
||||
<t:when-eq name="cur" value="val" />
|
||||
</c:value-of>
|
||||
</c:case>
|
||||
|
||||
<c:case label="Less than">
|
||||
<t:when-eq name="op" value="CMP_OP_LT" />
|
||||
|
||||
<c:value-of name="TRUE">
|
||||
<t:when-lt name="cur" value="val" />
|
||||
</c:value-of>
|
||||
</c:case>
|
||||
|
||||
<c:case label="Less than or equal to">
|
||||
<t:when-eq name="op" value="CMP_OP_LTE" />
|
||||
|
||||
<c:value-of name="TRUE">
|
||||
<t:when-lte name="cur" value="val" />
|
||||
</c:value-of>
|
||||
</c:case>
|
||||
|
||||
<c:case label="Greater than">
|
||||
<t:when-eq name="op" value="CMP_OP_GT" />
|
||||
|
||||
<c:value-of name="TRUE">
|
||||
<t:when-gt name="cur" value="val" />
|
||||
</c:value-of>
|
||||
</c:case>
|
||||
|
||||
<c:case label="Greater than or equal to">
|
||||
<t:when-eq name="op" value="CMP_OP_GTE" />
|
||||
|
||||
<c:value-of name="TRUE">
|
||||
<t:when-gte name="cur" value="val" />
|
||||
</c:value-of>
|
||||
</c:case>
|
||||
</c:cases>
|
||||
</c:value>
|
||||
</c:values>
|
||||
|
||||
<c:cases>
|
||||
<!-- if values matches, cons it -->
|
||||
<c:case>
|
||||
<t:when-eq name="found" value="TRUE" />
|
||||
|
||||
<c:cons>
|
||||
<c:value-of name="matrix">
|
||||
<c:index>
|
||||
<c:value-of name="start" />
|
||||
</c:index>
|
||||
</c:value-of>
|
||||
|
||||
<c:apply name="mrange" matrix="matrix" col="col" val="val"
|
||||
end="end" seq="seq" op="op">
|
||||
<c:arg name="start">
|
||||
<c:sum>
|
||||
<c:value-of name="start" />
|
||||
<c:const value="1" desc="Check next element" />
|
||||
</c:sum>
|
||||
</c:arg>
|
||||
</c:apply>
|
||||
</c:cons>
|
||||
</c:case>
|
||||
|
||||
|
||||
<!-- no match, continue (mutual) recursion -->
|
||||
<c:otherwise>
|
||||
<c:apply name="mrange" matrix="matrix" col="col" val="val"
|
||||
end="end" seq="seq">
|
||||
end="end" seq="seq" op="op">
|
||||
<c:arg name="start">
|
||||
<c:sum>
|
||||
<c:value-of name="start" />
|
||||
|
@ -245,21 +305,9 @@
|
|||
</c:sum>
|
||||
</c:arg>
|
||||
</c:apply>
|
||||
</c:cons>
|
||||
</c:case>
|
||||
|
||||
<c:otherwise>
|
||||
<c:apply name="mrange" matrix="matrix" col="col" val="val"
|
||||
end="end" seq="seq">
|
||||
<c:arg name="start">
|
||||
<c:sum>
|
||||
<c:value-of name="start" />
|
||||
<c:const value="1" desc="Check next element" />
|
||||
</c:sum>
|
||||
</c:arg>
|
||||
</c:apply>
|
||||
</c:otherwise>
|
||||
</c:cases>
|
||||
</c:otherwise>
|
||||
</c:cases>
|
||||
</c:let>
|
||||
</function>
|
||||
|
||||
|
||||
|
@ -329,16 +377,13 @@
|
|||
<c:cases>
|
||||
<!-- give up if we've reached our gap limit -->
|
||||
<c:case>
|
||||
<c:when name="gap">
|
||||
<c:lte>
|
||||
<c:value-of name="MFILTER_BISECT_GAP_MAX" />
|
||||
</c:lte>
|
||||
</c:when>
|
||||
<t:when-lte name="gap" value="MFILTER_BISECT_GAP_MAX" />
|
||||
|
||||
<!-- we tried our best; return our current position -->
|
||||
<c:value-of name="start" />
|
||||
</c:case>
|
||||
|
||||
|
||||
<!-- we have not yet reached our gap limit; keep going -->
|
||||
<c:otherwise>
|
||||
<c:let>
|
||||
|
@ -378,22 +423,14 @@
|
|||
<c:cases>
|
||||
<!-- if the middle value is lower than our value, then take the upper half -->
|
||||
<c:case>
|
||||
<c:when name="mid">
|
||||
<c:lt>
|
||||
<c:value-of name="val" />
|
||||
</c:lt>
|
||||
</c:when>
|
||||
<t:when-lt name="mid" value="val" />
|
||||
|
||||
<c:recurse start="mid_index" />
|
||||
</c:case>
|
||||
|
||||
<!-- similarily, take the lower half if we over-shot -->
|
||||
<c:case>
|
||||
<c:when name="mid">
|
||||
<c:gt>
|
||||
<c:value-of name="val" />
|
||||
</c:gt>
|
||||
</c:when>
|
||||
<t:when-gt name="mid" value="val" />
|
||||
|
||||
<c:recurse end="mid_index" />
|
||||
</c:case>
|
||||
|
@ -460,24 +497,14 @@
|
|||
<c:cases>
|
||||
<!-- if we have no more indexes to check, then we're done -->
|
||||
<c:case>
|
||||
<c:when name="i">
|
||||
<c:eq>
|
||||
<c:const value="0"
|
||||
desc="Did we check the final (first) index?" />
|
||||
</c:eq>
|
||||
</c:when>
|
||||
<t:when-eq name="i" value="#0" />
|
||||
|
||||
<!-- well, then, we're done -->
|
||||
<c:value-of name="i" />
|
||||
</c:case>
|
||||
|
||||
<!-- if the previous column value is the same value, then continue checking -->
|
||||
<c:case>
|
||||
<c:when name="prev">
|
||||
<c:eq>
|
||||
<c:value-of name="val" />
|
||||
</c:eq>
|
||||
</c:when>
|
||||
<t:when-eq name="prev" value="val" />
|
||||
|
||||
<c:recurse>
|
||||
<c:arg name="i">
|
||||
|
@ -507,23 +534,7 @@
|
|||
<c:cases>
|
||||
<!-- if masked -->
|
||||
<c:case>
|
||||
<!-- no index provided -->
|
||||
<unless name="@index@">
|
||||
<c:when name="@name@">
|
||||
<c:eq>
|
||||
<c:value-of name="FALSE" />
|
||||
</c:eq>
|
||||
</c:when>
|
||||
</unless>
|
||||
|
||||
<!-- index provided -->
|
||||
<if name="@index@">
|
||||
<c:when name="@name@" index="@index@">
|
||||
<c:eq>
|
||||
<c:value-of name="FALSE" />
|
||||
</c:eq>
|
||||
</c:when>
|
||||
</if>
|
||||
<t:when-eq name="@name@" index="@index@" value="FALSE" />
|
||||
|
||||
<!-- TODO: configurable mask via meta and/or param -->
|
||||
<c:value-of name="TABLE_WHEN_MASK_VALUE" />
|
||||
|
|
|
@ -202,10 +202,10 @@
|
|||
<t:query-field table="@table@"
|
||||
field="@field@">
|
||||
<!-- query for upper and lower values for interpolation -->
|
||||
<t:when field="@key@">
|
||||
<t:where-eq field="@key@">
|
||||
<c:value-of name="low" />
|
||||
<c:value-of name="high" />
|
||||
</t:when>
|
||||
</t:where-eq>
|
||||
|
||||
<param-copy name="@values@" />
|
||||
</t:query-field>
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
<!-- since templates are inlined, we need to make these symbols available to
|
||||
avoid terrible confusion -->
|
||||
<import package="../numeric/common" export="true"/>
|
||||
<import package="../when" export="true"/>
|
||||
<import package="common" export="true" />
|
||||
<import package="filter" export="true" />
|
||||
<import package="matrix" export="true" />
|
||||
|
@ -314,37 +315,78 @@
|
|||
<text>_RATE_TABLE</text>
|
||||
</param>
|
||||
|
||||
<c:apply name="_mquery">
|
||||
<c:arg name="matrix">
|
||||
<c:value-of name="@matrix@" />
|
||||
</c:arg>
|
||||
|
||||
<c:arg name="criteria">
|
||||
<c:vector>
|
||||
<param-copy name="@values@">
|
||||
<param-meta name="table_basename" value="@matrix@" />
|
||||
</param-copy>
|
||||
</c:vector>
|
||||
</c:arg>
|
||||
<c:let>
|
||||
<c:values>
|
||||
<c:value name="_qparams" type="integer" set="matrix"
|
||||
desc="Query parameters">
|
||||
<c:vector>
|
||||
<param-copy name="@values@">
|
||||
<param-meta name="table_basename" value="@matrix@" />
|
||||
</param-copy>
|
||||
</c:vector>
|
||||
</c:value>
|
||||
</c:values>
|
||||
|
||||
<c:arg name="i">
|
||||
<!-- begin with the last predicate (due to the way we'll recurse, it
|
||||
will be applied *last* -->
|
||||
<t:dec>
|
||||
<c:length-of>
|
||||
<c:vector>
|
||||
<param-copy name="@values@">
|
||||
<param-meta name="table_basename" value="@matrix@" />
|
||||
</param-copy>
|
||||
</c:vector>
|
||||
</c:length-of>
|
||||
</t:dec>
|
||||
</c:arg>
|
||||
</c:apply>
|
||||
|
||||
<c:apply name="_mquery" matrix="@matrix@">
|
||||
<c:arg name="criteria">
|
||||
<c:value-of name="_qparams" />
|
||||
</c:arg>
|
||||
|
||||
<c:arg name="i">
|
||||
<!-- begin with the last predicate (due to the way we'll recurse, it
|
||||
will be applied *last* -->
|
||||
<t:dec>
|
||||
<c:length-of>
|
||||
<c:value-of name="_qparams" />
|
||||
</c:length-of>
|
||||
</t:dec>
|
||||
</c:arg>
|
||||
</c:apply>
|
||||
</c:let>
|
||||
</template>
|
||||
|
||||
|
||||
<template name="_when_" desc="Create field predicate for query definition">
|
||||
There are a series of \tt{_where-*_} templates for query predicates that
|
||||
are analogous to the \tt{_match-*_} and \tt{_when-*_} templates used in
|
||||
other contexts.
|
||||
|
||||
<inline-template>
|
||||
<for-each>
|
||||
<set tplname="_where-eq_" op="CMP_OP_EQ" desc="equal" />
|
||||
<set tplname="_where-lt_" op="CMP_OP_LT" desc="less than" />
|
||||
<set tplname="_where-lte_" op="CMP_OP_LTE" desc="less than or equal to" />
|
||||
<set tplname="_where-gt_" op="CMP_OP_GT" desc="greater than" />
|
||||
<set tplname="_where-gte_" op="CMP_OP_GTE" desc="greater than or equal to" />
|
||||
</for-each>
|
||||
|
||||
|
||||
<template name="@tplname@" desc="Field predicate for table query ({@desc@})">
|
||||
<param name="@values@" desc="Field value (provide only one node)" />
|
||||
<param name="@id@" desc="Field index" />
|
||||
<param name="@field@" desc="Field name (to be used with base)" />
|
||||
|
||||
<param name="@name@" desc="Field name (as a variable/constant)">
|
||||
<text></text>
|
||||
</param>
|
||||
|
||||
<param name="@seqvar@" desc="Var/constant containing whether field is sequential">
|
||||
<text></text>
|
||||
</param>
|
||||
|
||||
|
||||
<t:where id="@id@" seqvar="@seqvar@"
|
||||
field="@field@" name="@name@" op="@op@">
|
||||
<expand-barrier>
|
||||
<param-copy name="@values@" />
|
||||
</expand-barrier>
|
||||
</t:where>
|
||||
</template>
|
||||
</inline-template>
|
||||
|
||||
|
||||
<template name="_where_" desc="Create field predicate for query definition">
|
||||
<param name="@id@" desc="Field index" />
|
||||
<param name="@values@" desc="Field value (provide only one node)" />
|
||||
<param name="@sequential@" desc="Is data sequential?" />
|
||||
|
@ -367,6 +409,12 @@
|
|||
<text>_IS_SEQ</text>
|
||||
</param>
|
||||
|
||||
<param name="@op@"
|
||||
desc="Comparison operator (default CMP_OP_EQ; see CmpOp typedef)">
|
||||
<text>CMP_OP_EQ</text>
|
||||
</param>
|
||||
|
||||
|
||||
<c:vector label="Conditional for {@field@}">
|
||||
<!-- the first element will represent the column (field) index -->
|
||||
<unless name="@name@">
|
||||
|
@ -381,7 +429,7 @@
|
|||
<param-copy name="@values@" />
|
||||
</c:vector>
|
||||
|
||||
<!-- the final element will represent whether or not this field is sequential -->
|
||||
<!-- the third element will represent whether or not this field is sequential -->
|
||||
<if name="@sequential@">
|
||||
<c:const value="@sequential@" type="boolean" desc="Whether data is sequential" />
|
||||
</if>
|
||||
|
@ -396,10 +444,53 @@
|
|||
<c:value-of name="FALSE" />
|
||||
</unless>
|
||||
</unless>
|
||||
|
||||
<!-- the fourth and final element is the comparison operator -->
|
||||
<c:value-of name="@op@" />
|
||||
</c:vector>
|
||||
</template>
|
||||
|
||||
|
||||
<!--
|
||||
_when_ is deprecated in favor of _where-eq_.
|
||||
|
||||
This old template aimed to be consistent with the use of `when'
|
||||
elsewhere (for cases and value predicates), but it was awkward in a
|
||||
query abstraction.
|
||||
-->
|
||||
<template name="_when_"
|
||||
desc="Create field predicate for query definition (deprecated;
|
||||
use _where-*_)">
|
||||
<param name="@values@" desc="Field value (provide only one node)" />
|
||||
<param name="@id@" desc="Field index" />
|
||||
<param name="@sequential@" desc="Is data sequential?" />
|
||||
<param name="@field@" desc="Field name (to be used with base)" />
|
||||
|
||||
<param name="@name@" desc="Field name (as a variable/constant)">
|
||||
<text></text>
|
||||
</param>
|
||||
|
||||
<param name="@seqvar@" desc="Var/constant containing whether field is sequential">
|
||||
<text></text>
|
||||
</param>
|
||||
|
||||
<param name="@op@"
|
||||
desc="Comparison operator (default CMP_OP_EQ; see CmpOp typedef)">
|
||||
<text></text>
|
||||
</param>
|
||||
|
||||
|
||||
<warning>
|
||||
_when_ is deprecated; use _where-eq_ instead
|
||||
</warning>
|
||||
|
||||
<t:where id="@id@" sequential="@sequential@" seqvar="@seqvar@"
|
||||
field="@field@" name="@name@" op="CMP_OP_EQ">
|
||||
<param-copy name="@values@" />
|
||||
</t:where>
|
||||
</template>
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
These functions make the magic happen
|
||||
|
@ -417,38 +508,27 @@
|
|||
|
||||
<c:cases>
|
||||
<c:case>
|
||||
<c:when name="i">
|
||||
<c:eq>
|
||||
<!-- it's important that we allow index 0, since that is a valid
|
||||
predicate -->
|
||||
<c:const value="-1" type="integer" desc="We're done." />
|
||||
</c:eq>
|
||||
</c:when>
|
||||
<!-- it's important that we allow index 0, since that is a valid
|
||||
predicate -->
|
||||
<t:when-eq name="i" value="#-1" />
|
||||
|
||||
<!-- we're done; stick with the result -->
|
||||
<c:value-of name="matrix" />
|
||||
</c:case>
|
||||
|
||||
|
||||
<c:otherwise>
|
||||
<c:apply name="mfilter">
|
||||
<!-- matrix to search -->
|
||||
<c:arg name="matrix">
|
||||
<!-- >> recursion happens here << -->
|
||||
<c:apply name="_mquery">
|
||||
<c:arg name="matrix">
|
||||
<c:value-of name="matrix" />
|
||||
</c:arg>
|
||||
|
||||
<c:arg name="criteria">
|
||||
<c:value-of name="criteria" />
|
||||
</c:arg>
|
||||
|
||||
<c:recurse>
|
||||
<c:arg name="i">
|
||||
<t:dec>
|
||||
<c:value-of name="i" />
|
||||
</t:dec>
|
||||
</c:arg>
|
||||
</c:apply>
|
||||
</c:recurse>
|
||||
</c:arg>
|
||||
|
||||
<!-- field (column) -->
|
||||
|
@ -486,6 +566,18 @@
|
|||
</c:index>
|
||||
</c:value-of>
|
||||
</c:arg>
|
||||
|
||||
<!-- comparison operator -->
|
||||
<c:arg name="op">
|
||||
<c:value-of name="criteria">
|
||||
<c:index>
|
||||
<c:value-of name="i" />
|
||||
</c:index>
|
||||
<c:index>
|
||||
<c:const value="3" type="integer" desc="Comparison operator" />
|
||||
</c:index>
|
||||
</c:value-of>
|
||||
</c:arg>
|
||||
</c:apply>
|
||||
</c:otherwise>
|
||||
</c:cases>
|
||||
|
|
|
@ -150,7 +150,7 @@
|
|||
</xs:annotation>
|
||||
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="_[a-zA-Z0-9@\{\}-]+_" />
|
||||
<xs:pattern value="_[a-zA-Z0-9@\{\}-]+_|@[a-z][a-zA-Z0-9]*@" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
|
|
|
@ -693,6 +693,7 @@
|
|||
<xs:sequence>
|
||||
<xs:element name="when" type="whenType" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xs:element name="index" type="indexType" minOccurs="0" maxOccurs="2" />
|
||||
<xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
|
||||
</xs:sequence>
|
||||
|
||||
<xs:attribute name="name" type="nameType" use="required">
|
||||
|
|
|
@ -145,7 +145,7 @@
|
|||
</xs:annotation>
|
||||
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="_[a-zA-Z0-9@\{\}-]+_" />
|
||||
<xs:pattern value="_[a-zA-Z0-9@\{\}-]+_|@[a-z][a-zA-Z0-9]*@" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
|
|
Loading…
Reference in New Issue