Mike Gerwitz

Activist for User Freedom

aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Gerwitz <mike.gerwitz@rtspecialty.com>2018-01-26 11:21:01 -0500
committerMike Gerwitz <mike.gerwitz@rtspecialty.com>2018-09-11 09:30:52 -0400
commitec7d1c2a24ac07b240d8fa95aaa831bb067dd1fe (patch)
treee19081b001fc685c396efa5b68f54bd3c5deb7fc
parenta10adcbe1cba6a35538dfd439eb9382f7cbac4a1 (diff)
downloadtame-ec7d1c2a24ac07b240d8fa95aaa831bb067dd1fe.tar.gz
tame-ec7d1c2a24ac07b240d8fa95aaa831bb067dd1fe.tar.bz2
tame-ec7d1c2a24ac07b240d8fa95aaa831bb067dd1fe.zip
vector/table: Extract mfilter and range into vector/filter
* vector/filter.xml: New package. * vector/table.xml (mfilter, _mfilter, range): Extract into vector/filter.
-rw-r--r--core/vector/filter.xml233
-rw-r--r--core/vector/table.xml209
2 files changed, 235 insertions, 207 deletions
diff --git a/core/vector/filter.xml b/core/vector/filter.xml
new file mode 100644
index 0000000..b679c7d
--- /dev/null
+++ b/core/vector/filter.xml
@@ -0,0 +1,233 @@
+<?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"
+ core="true"
+ desc="Filtering Vectors and Matrices">
+
+
+ <section title="Matrix Filtering">
+ <function name="mfilter" desc="Filter matrix rows by column value">
+ <param name="matrix" type="float" set="matrix" desc="Matrix to filter" />
+ <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?" />
+
+ <!-- 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
+ data (or just one, if they don't want to feel sweet). By performing
+ 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="range" matrix="matrix" col="col" val="val" seq="seq">
+ <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) -->
+ <c:case>
+ <c:when name="seq">
+ <c:eq>
+ <c:value-of name="TRUE" />
+ </c:eq>
+ </c:when>
+
+ <c:apply name="bisect" matrix="matrix" col="col" val="val">
+ <c:arg name="start">
+ <c:const value="0" type="integer" desc="Start bisect at beginning" />
+ </c:arg>
+
+ <c:arg name="end">
+ <!-- bisect the length of the matrix -->
+ <t:dec>
+ <c:length-of>
+ <c:value-of name="matrix" />
+ </c:length-of>
+ </t:dec>
+ </c:arg>
+ </c:apply>
+ </c:case>
+
+ <!-- we have no good guess; linear search :x -->
+ <c:otherwise>
+ <c:const value="0" type="integer" desc="Start at the first element" />
+ </c:otherwise>
+ </c:cases>
+ </c:arg>
+
+ <c:arg name="end">
+ <t:dec>
+ <c:length-of>
+ <c:value-of name="matrix" />
+ </c:length-of>
+ </t:dec>
+ </c:arg>
+ </c:apply>
+ </t:merge-until-empty>
+ </function>
+
+
+ <function name="range" desc="Filter matrix rows by column value within a certain range of indexes (inclusive)">
+ <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 (inclusive)" />
+ <param name="end" type="integer" desc="Ending index (inclusive)" />
+ <param name="seq" type="boolean" desc="Is data sequential?" />
+
+ <c:let>
+ <c:values>
+ <c:value name="curval" type="float" desc="Current value">
+ <c:value-of name="matrix">
+ <c:index>
+ <c:value-of name="start" />
+ </c:index>
+
+ <c:index>
+ <c:value-of name="col" />
+ </c:index>
+ </c:value-of>
+ </c:value>
+ </c:values>
+
+ <!-- nested let needed so that the curval is available to over
+ in the body below -->
+ <c:let>
+ <c:values>
+ <!-- determine if the value we're looking for is over the current value
+ in a sorted list (meaning that we will not find it) -->
+ <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>
+ </c:value-of>
+ </c:value>
+ </c:values>
+
+ <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>
+
+ <!-- empty set -->
+ <c:set />
+ </c:case>
+
+ <!-- if the data is sequential and the next element is over the
+ requested value, then we're done -->
+ <c:case>
+ <c:when name="over">
+ <c:eq>
+ <c:value-of name="TRUE" />
+ </c:eq>
+ </c:when>
+
+ <!-- empty set -->
+ <c:set />
+ </c:case>
+
+
+ <c:otherwise>
+ <c:apply name="_mfilter" matrix="matrix" col="col" val="val" start="start" end="end" seq="seq">
+ <c:arg name="cur">
+ <c:value-of name="matrix">
+ <!-- current row -->
+ <c:index>
+ <c:value-of name="start" />
+ </c:index>
+
+ <!-- requested column -->
+ <c:index>
+ <c:value-of name="col" />
+ </c:index>
+ </c:value-of>
+ </c:arg>
+ </c:apply>
+ </c:otherwise>
+ </c:cases>
+ </c:let>
+ </c:let>
+ </function>
+
+
+ <function name="_mfilter" desc="mfilter helper">
+ <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="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:apply name="range" 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" type="integer" desc="Check next element" />
+ </c:sum>
+ </c:arg>
+ </c:apply>
+ </c:cons>
+ </c:case>
+
+ <c:otherwise>
+ <c:apply name="range" 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" type="integer" desc="Check next element" />
+ </c:sum>
+ </c:arg>
+ </c:apply>
+ </c:otherwise>
+ </c:cases>
+ </function>
+ </section>
+</package>
diff --git a/core/vector/table.xml b/core/vector/table.xml
index 646e83b..c74ac9a 100644
--- a/core/vector/table.xml
+++ b/core/vector/table.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
- Copyright (C) 2015 R-T Specialty, LLC.
+ Copyright (C) 2015, 2018 R-T Specialty, LLC.
This file is part of tame-core.
@@ -30,6 +30,7 @@
avoid terrible confusion -->
<import package="../numeric/common" export="true"/>
<import package="common" export="true" />
+ <import package="filter" export="true" />
<import package="matrix" export="true" />
@@ -752,211 +753,5 @@
</c:otherwise>
</c:cases>
</template>
-
-
- <function name="mfilter" desc="Filter matrix rows by column value">
- <param name="matrix" type="float" set="matrix" desc="Matrix to filter" />
- <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?" />
-
- <!-- 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
- data (or just one, if they don't want to feel sweet). By performing
- 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="range" matrix="matrix" col="col" val="val" seq="seq">
- <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) -->
- <c:case>
- <c:when name="seq">
- <c:eq>
- <c:value-of name="TRUE" />
- </c:eq>
- </c:when>
-
- <c:apply name="bisect" matrix="matrix" col="col" val="val">
- <c:arg name="start">
- <c:const value="0" type="integer" desc="Start bisect at beginning" />
- </c:arg>
-
- <c:arg name="end">
- <!-- bisect the length of the matrix -->
- <t:dec>
- <c:length-of>
- <c:value-of name="matrix" />
- </c:length-of>
- </t:dec>
- </c:arg>
- </c:apply>
- </c:case>
-
- <!-- we have no good guess; linear search :x -->
- <c:otherwise>
- <c:const value="0" type="integer" desc="Start at the first element" />
- </c:otherwise>
- </c:cases>
- </c:arg>
-
- <c:arg name="end">
- <t:dec>
- <c:length-of>
- <c:value-of name="matrix" />
- </c:length-of>
- </t:dec>
- </c:arg>
- </c:apply>
- </t:merge-until-empty>
- </function>
-
-
- <function name="range" desc="Filter matrix rows by column value within a certain range of indexes (inclusive)">
- <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 (inclusive)" />
- <param name="end" type="integer" desc="Ending index (inclusive)" />
- <param name="seq" type="boolean" desc="Is data sequential?" />
-
- <c:let>
- <c:values>
- <c:value name="curval" type="float" desc="Current value">
- <c:value-of name="matrix">
- <c:index>
- <c:value-of name="start" />
- </c:index>
-
- <c:index>
- <c:value-of name="col" />
- </c:index>
- </c:value-of>
- </c:value>
- </c:values>
-
- <!-- nested let needed so that the curval is available to over
- in the body below -->
- <c:let>
- <c:values>
- <!-- determine if the value we're looking for is over the current value
- in a sorted list (meaning that we will not find it) -->
- <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>
- </c:value-of>
- </c:value>
- </c:values>
-
- <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>
-
- <!-- empty set -->
- <c:set />
- </c:case>
-
- <!-- if the data is sequential and the next element is over the
- requested value, then we're done -->
- <c:case>
- <c:when name="over">
- <c:eq>
- <c:value-of name="TRUE" />
- </c:eq>
- </c:when>
-
- <!-- empty set -->
- <c:set />
- </c:case>
-
-
- <c:otherwise>
- <c:apply name="_mfilter" matrix="matrix" col="col" val="val" start="start" end="end" seq="seq">
- <c:arg name="cur">
- <c:value-of name="matrix">
- <!-- current row -->
- <c:index>
- <c:value-of name="start" />
- </c:index>
-
- <!-- requested column -->
- <c:index>
- <c:value-of name="col" />
- </c:index>
- </c:value-of>
- </c:arg>
- </c:apply>
- </c:otherwise>
- </c:cases>
- </c:let>
- </c:let>
- </function>
-
-
- <function name="_mfilter" desc="mfilter helper">
- <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="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:apply name="range" 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" type="integer" desc="Check next element" />
- </c:sum>
- </c:arg>
- </c:apply>
- </c:cons>
- </c:case>
-
- <c:otherwise>
- <c:apply name="range" 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" type="integer" desc="Check next element" />
- </c:sum>
- </c:arg>
- </c:apply>
- </c:otherwise>
- </c:cases>
- </function>
</package>