diff --git a/.DS_Store b/.DS_Store index 6d849f5..ef83734 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.Rbuildignore b/.Rbuildignore index 782dcb7..1518f0d 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -7,3 +7,5 @@ ^cleanup\.R$ ^experiments\.R$ ^.imdone$ +^cran-comments\.md$ +^docs$ diff --git a/DESCRIPTION b/DESCRIPTION index bf7bbdc..eb0e37d 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,8 +1,10 @@ Package: dynprog -Version: 0.0.0.9000 -Title: Dynamic Programming DSL -Description: A domain-specific langauge for specifying dynamic-programming - algorithms. +Version: 0.1.0 +Title: Dynamic Programming Domain-Specific Language +Description: A domain-specific language for specifying translating recursions + into dynamic-programming algorithms. See + for a description + of dynamic programming. Authors@R: person("Thomas", "Mailund", email = "mailund@birc.au.dk", role = c("aut", "cre")) diff --git a/NEWS.md b/NEWS.md index 2f75f99..d251537 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,4 @@ -# dynprog 0.0.0.9000 +# dynprog 0.1.0 -* Initial package setup. +* Initial release. diff --git a/R/dsl.R b/R/dsl.R index 6b64fd3..1adfa0b 100644 --- a/R/dsl.R +++ b/R/dsl.R @@ -10,6 +10,33 @@ #' compute values over. #' #' @return A filled out dynamic programming table. +#' @examples +#' +#' # Fibonnaci numbers +#' fib <- { +#' F[n] <- 1 ? n <= 2 +#' F[n] <- F[n-1] + F[n-2] +#' } %where% { +#' n <- 1:10 +#' } +#' fib +#' +#' # Edit distance +#' x <- c("a", "b", "c") +#' y <- c("a", "b", "b", "c") +#' edit <- { +#' E[1,j] <- j - 1 +#' E[i,1] <- i - 1 +#' E[i,j] <- min( +#' E[i - 1,j] + 1, +#' E[i,j - 1] + 1, +#' E[i - 1,j - 1] + (x[i - 1] != y[j - 1]) +#' ) +#' } %where% { +#' i <- 1:(length(x) + 1) +#' j <- 1:(length(y) + 1) +#' } +#' edit #' #' @export `%where%` <- function(recursion, ranges) { diff --git a/R/evaluate.R b/R/evaluate.R index 878e72e..7ba3c18 100644 --- a/R/evaluate.R +++ b/R/evaluate.R @@ -61,7 +61,7 @@ make_pattern_tests <- function(patterns, range_vars) { #' @param patterns The patterns specifications #' @param conditions The conditions specifications #' @param recursions The recursions specification -#' @return A list of calls, one per recurision, for testing conditions. +#' @return A list of calls, one per recursion, for testing conditions. make_condition_checks <- function(ranges, patterns, conditions, @@ -129,7 +129,7 @@ make_update_expr <- function(ranges, #' evaluate the dynprog expression, returning a filled out dynamic programming #' table. #' -#' @param ranges The ranges specificatoin +#' @param ranges The ranges specification #' @param recursions The recursions specification #' @return The filled out dynamic programming table eval_recursion <- function(ranges, recursions) { diff --git a/R/parser.R b/R/parser.R index a77f069..ed2683c 100644 --- a/R/parser.R +++ b/R/parser.R @@ -52,7 +52,7 @@ parse_ranges <- function(ranges) { #' The parser return a list with the following components: #' - **recursion_env:** The environment in which expressions should be #' evaluated. -#' - **partterns:** A list of patterns, one per recursion case. +#' - **patterns:** A list of patterns, one per recursion case. #' - **conditions:** A list of conditions, one per recursion case. #' - **recursions:** A list of expressions, one per recursion case. #' diff --git a/README.Rmd b/README.Rmd index 190280c..4a615c5 100644 --- a/README.Rmd +++ b/README.Rmd @@ -21,13 +21,11 @@ library(dynprog) [![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](http://www.repostatus.org/badges/latest/active.svg)](http://www.repostatus.org/#active) [![lifecycle](http://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://www.tidyverse.org/lifecycle/#experimental) [![Last-changedate](https://img.shields.io/badge/last%20change-`r gsub('-', '--', Sys.Date())`-orange.svg)](/commits/master) -[![packageversion](https://img.shields.io/badge/Package%20version-0.0.0.9000-orange.svg?style=flat-square)](commits/master) - +[![packageversion](https://img.shields.io/badge/Package%20version-0.1.0-orange.svg?style=flat-square)](commits/master) [![Travis build status](https://travis-ci.org/mailund/dynprog.svg?branch=master)](https://travis-ci.org/mailund/dynprog) [![AppVeyor build status](https://ci.appveyor.com/api/projects/status/github/mailund/dynprog?branch=master&svg=true)](https://ci.appveyor.com/project/mailund/dynprog) [![Coverage status](https://codecov.io/gh/mailund/dynprog/branch/master/graph/badge.svg)](https://codecov.io/github/mailund/dynprog?branch=master) [![Coverage status](http://coveralls.io/repos/github/mailund/dynprog/badge.svg?branch=master)](https://coveralls.io/github/mailund/dynprog?branch=master) - [![CRAN status](http://www.r-pkg.org/badges/version/dynprog)](https://cran.r-project.org/package=dynprog) [![CRAN downloads](http://cranlogs.r-pkg.org/badges/grand-total/dynprog)](https://cran.r-project.org/package=dynprog) [![minimal R version](https://img.shields.io/badge/R-%E2%89%A53.1-blue.svg)](https://cran.r-project.org/) diff --git a/README.md b/README.md index 27d05fb..f5d7f20 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,7 @@ state and is being actively developed.](http://www.repostatus.org/badges/latest/active.svg)](http://www.repostatus.org/#active) [![lifecycle](http://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://www.tidyverse.org/lifecycle/#experimental) [![Last-changedate](https://img.shields.io/badge/last%20change-2018--03--24-orange.svg)](/commits/master) -[![packageversion](https://img.shields.io/badge/Package%20version-0.0.0.9000-orange.svg?style=flat-square)](commits/master) - +[![packageversion](https://img.shields.io/badge/Package%20version-0.1.0-orange.svg?style=flat-square)](commits/master) [![Travis build status](https://travis-ci.org/mailund/dynprog.svg?branch=master)](https://travis-ci.org/mailund/dynprog) [![AppVeyor build @@ -19,7 +18,6 @@ status](https://ci.appveyor.com/api/projects/status/github/mailund/dynprog?branc status](https://codecov.io/gh/mailund/dynprog/branch/master/graph/badge.svg)](https://codecov.io/github/mailund/dynprog?branch=master) [![Coverage status](http://coveralls.io/repos/github/mailund/dynprog/badge.svg?branch=master)](https://coveralls.io/github/mailund/dynprog?branch=master) - [![CRAN status](http://www.r-pkg.org/badges/version/dynprog)](https://cran.r-project.org/package=dynprog) [![CRAN diff --git a/cran-comments.md b/cran-comments.md new file mode 100644 index 0000000..97143a6 --- /dev/null +++ b/cran-comments.md @@ -0,0 +1,34 @@ +# dynprog: Domain-specific langauge for specifying dynamic programming algorithms. + +Implements a small domain-specific language that translates recursions into +dynamic programming computations. + +This is a resubmission with changes based on email. I have: + + - Added examples so "checking examples" should not show NONE. + - %where% is the only exported function, so the examples are there + - I have added a reference to Dynamic Programming on Wikipedia + (it is a common algorithmic technique, so there is no obvious + paper to quote; the paper introducing it is dated compared to + modern algorithmic textbooks). + +## Test environments +* local OS X install, R 3.4.4 +* ubuntu 14.04 (on travis-ci), R 3.4.4 +* win-builder (devel and release) +* RHub: + + - Fedora Linux, R-devel, clang, gfortran + - Ubuntu Linux 16.04 LTS, R-release, GCC + - Windows Server 2008 R2 SP1, R-devel, 32/64 bit + + On RHub on Windows a warning that Pandoc cannot + find the badges images (which Pandoc always complain about on Windows). + + Other than that, the package checks. + +## R CMD check results + +0 errors | 0 warnings | 1 note + +* This is a new release. diff --git a/docs/authors.html b/docs/authors.html new file mode 100644 index 0000000..10d6f76 --- /dev/null +++ b/docs/authors.html @@ -0,0 +1,140 @@ + + + + + + + + +Citation and Authors • dynprog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ +
+
+ + + +

Mailund T (2018). +Domain-Specific Languages in R: Advanced Statistical Programming. +Apress. +ISBN 1484235878, https://amzn.to/2DRmFXb. +

+
@Book{,
+  author = {Thomas Mailund},
+  title = {Domain-Specific Languages in R: Advanced Statistical Programming},
+  publisher = {Apress},
+  year = {2018},
+  url = {https://amzn.to/2DRmFXb},
+  isbn = {1484235878},
+}
+ + +
    +
  • +

    Thomas Mailund. Author, maintainer. +

    +
  • +
+ +
+ +
+ + +
+ + +
+

Site built with pkgdown.

+
+ +
+
+ + + + diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..6b806e7 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,219 @@ + + + + + + + +Dynamic Programming Domain-Specific Language • dynprog + + + + + + + + + +
+
+ + + +
+
+ + + + +
+ +
+ + +

The dynprog package implements a small domain-specific language for specifying dynamic programming algorithms. It allows you to specify a computation as a recursion and it will then use this recursion to fill out a table and return it to you.

+

As a very simple example, you can specify a dynamic programming computation of Fibonnaci numbers using

+ +

As shown in the example, the expression consists of two parts, the first, before the %where% operator, describes a recursion and the second, after the %where% operator, the range the variable n should iterate over.

+

Formally, a dynprog expression is on the form

+
DYNPROG_EXPR ::= RECURSIONS '%where%' RANGES
+RECURSIONS ::= '{' PATTERN_ASSIGNMENTS '}'
+RANGES ::= '{' RANGES_ASSIGNMENTS '}'
+

where PATTERN_ASSIGNMENTS describe the recursion and RANGES_ASSIGNMENTS the variables to recurse over and the values those variables should take.

+

Ranges are the simplest of the two.

+
RANGES_ASSIGNMENTS ::= RANGES_ASSIGNMENT
+                    |  RANGES_ASSIGNMENT ';' RANGES_ASSIGNMENTS
+RANGES_ASSIGNMENT ::= RANGE_INDEX '<-' RANGE_EXPRESSION
+

where RANGE_INDEX is just a variable and RANGE_EXPRESSION an expression that should evaluate to a list or vector. You can specify more than one variable if these are separated by ; or newlines (the grammar only says ; but I am not too formal here). An example with two range variables, of computing the edit distance between two strings, is shown below.

+

The actual recursions are specified in PATTERN_ASSIGNMENTS:

+
PATTERN_ASSIGNMENTS ::= PATTERN_ASSIGNMENT
+                     |  PATTERN_ASSIGNMENT ';' PATTERN_ASSIGNMENTS
+

where

+
PATTERN_ASSIGNMENT ::= PATTERN '<-' RECURSION
+                    |  PATTERN '<-' RECURSION '?' CONDITION
+
PATTERN ::= TABLE '[' INDICES ']'
+

Here, TABLE is just a variable and INDICES should be a comma-separated lists of values/expressions or variables. When recursions are evaluated, the range variables are tested against the patterns. If a pattern contains a range variable as a variable, the variable is free to take any value, but if it takes on a value, the range variable must have that value.

+

To the right of the assignment in PATTERN_ASSIGNMENTS we have RECURSION, which cna be any R expression and an optional CONDITION, which should be an R expression that evaluates to a boolean value.

+

The semantics of the recursions are that the patterns are tested in the order they are provided, and if both the patterns match the range variables and the condition evaluates to TRUE, then the entry in the table will get assigned the result of evaluating RECURSION.

+

For more information, see

+
+

Mailund, T. (2018) Domain-Specific Languages in R, Apress. ISBN 1484235878

+
+
+

+Installation

+

You can install the released version of dynprog from CRAN with:

+ +

and the development version from GitHub with:

+ +
+ +
+
+
+ + + +
+ + +
+ +
+

Site built with pkgdown.

+
+ +
+
+ + + diff --git a/docs/jquery.sticky-kit.min.js b/docs/jquery.sticky-kit.min.js new file mode 100644 index 0000000..e2a3c6d --- /dev/null +++ b/docs/jquery.sticky-kit.min.js @@ -0,0 +1,9 @@ +/* + Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net +*/ +(function(){var b,f;b=this.jQuery||window.jQuery;f=b(window);b.fn.stick_in_parent=function(d){var A,w,J,n,B,K,p,q,k,E,t;null==d&&(d={});t=d.sticky_class;B=d.inner_scrolling;E=d.recalc_every;k=d.parent;q=d.offset_top;p=d.spacer;w=d.bottoming;null==q&&(q=0);null==k&&(k=void 0);null==B&&(B=!0);null==t&&(t="is_stuck");A=b(document);null==w&&(w=!0);J=function(a,d,n,C,F,u,r,G){var v,H,m,D,I,c,g,x,y,z,h,l;if(!a.data("sticky_kit")){a.data("sticky_kit",!0);I=A.height();g=a.parent();null!=k&&(g=g.closest(k)); +if(!g.length)throw"failed to find stick parent";v=m=!1;(h=null!=p?p&&a.closest(p):b("
"))&&h.css("position",a.css("position"));x=function(){var c,f,e;if(!G&&(I=A.height(),c=parseInt(g.css("border-top-width"),10),f=parseInt(g.css("padding-top"),10),d=parseInt(g.css("padding-bottom"),10),n=g.offset().top+c+f,C=g.height(),m&&(v=m=!1,null==p&&(a.insertAfter(h),h.detach()),a.css({position:"",top:"",width:"",bottom:""}).removeClass(t),e=!0),F=a.offset().top-(parseInt(a.css("margin-top"),10)||0)-q, +u=a.outerHeight(!0),r=a.css("float"),h&&h.css({width:a.outerWidth(!0),height:u,display:a.css("display"),"vertical-align":a.css("vertical-align"),"float":r}),e))return l()};x();if(u!==C)return D=void 0,c=q,z=E,l=function(){var b,l,e,k;if(!G&&(e=!1,null!=z&&(--z,0>=z&&(z=E,x(),e=!0)),e||A.height()===I||x(),e=f.scrollTop(),null!=D&&(l=e-D),D=e,m?(w&&(k=e+u+c>C+n,v&&!k&&(v=!1,a.css({position:"fixed",bottom:"",top:c}).trigger("sticky_kit:unbottom"))),eb&&!v&&(c-=l,c=Math.max(b-u,c),c=Math.min(q,c),m&&a.css({top:c+"px"})))):e>F&&(m=!0,b={position:"fixed",top:c},b.width="border-box"===a.css("box-sizing")?a.outerWidth()+"px":a.width()+"px",a.css(b).addClass(t),null==p&&(a.after(h),"left"!==r&&"right"!==r||h.append(a)),a.trigger("sticky_kit:stick")),m&&w&&(null==k&&(k=e+u+c>C+n),!v&&k)))return v=!0,"static"===g.css("position")&&g.css({position:"relative"}), +a.css({position:"absolute",bottom:d,top:"auto"}).trigger("sticky_kit:bottom")},y=function(){x();return l()},H=function(){G=!0;f.off("touchmove",l);f.off("scroll",l);f.off("resize",y);b(document.body).off("sticky_kit:recalc",y);a.off("sticky_kit:detach",H);a.removeData("sticky_kit");a.css({position:"",bottom:"",top:"",width:""});g.position("position","");if(m)return null==p&&("left"!==r&&"right"!==r||a.insertAfter(h),h.remove()),a.removeClass(t)},f.on("touchmove",l),f.on("scroll",l),f.on("resize", +y),b(document.body).on("sticky_kit:recalc",y),a.on("sticky_kit:detach",H),setTimeout(l,0)}};n=0;for(K=this.length;n + + + + + diff --git a/docs/news/index.html b/docs/news/index.html new file mode 100644 index 0000000..70ec3f9 --- /dev/null +++ b/docs/news/index.html @@ -0,0 +1,134 @@ + + + + + + + + +Changelog • dynprog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ +
+ + +
+
+

+dynprog 0.1.0

+
    +
  • Initial release.
  • +
+
+
+
+ + + +
+ +
+ + +
+

Site built with pkgdown.

+
+ +
+
+ + + + diff --git a/docs/pkgdown.css b/docs/pkgdown.css new file mode 100644 index 0000000..fcd97bb --- /dev/null +++ b/docs/pkgdown.css @@ -0,0 +1,219 @@ +/* Sticky footer */ + +/** + * Basic idea: https://philipwalton.github.io/solved-by-flexbox/demos/sticky-footer/ + * Details: https://github.com/philipwalton/solved-by-flexbox/blob/master/assets/css/components/site.css + * + * .Site -> body > .container + * .Site-content -> body > .container .row + * .footer -> footer + * + * Key idea seems to be to ensure that .container and __all its parents__ + * have height set to 100% + * + */ + +html, body { + height: 100%; +} + +body > .container { + display: flex; + height: 100%; + flex-direction: column; + + padding-top: 60px; +} + +body > .container .row { + flex: 1 0 auto; +} + +footer { + margin-top: 45px; + padding: 35px 0 36px; + border-top: 1px solid #e5e5e5; + color: #666; + display: flex; + flex-shrink: 0; +} +footer p { + margin-bottom: 0; +} +footer div { + flex: 1; +} +footer .pkgdown { + text-align: right; +} +footer p { + margin-bottom: 0; +} + +img.icon { + float: right; +} + +img { + max-width: 100%; +} + +/* Typographic tweaking ---------------------------------*/ + +.contents h1.page-header { + margin-top: calc(-60px + 1em); +} + +/* Section anchors ---------------------------------*/ + +a.anchor { + margin-left: -30px; + display:inline-block; + width: 30px; + height: 30px; + visibility: hidden; + + background-image: url(./link.svg); + background-repeat: no-repeat; + background-size: 20px 20px; + background-position: center center; +} + +.hasAnchor:hover a.anchor { + visibility: visible; +} + +@media (max-width: 767px) { + .hasAnchor:hover a.anchor { + visibility: hidden; + } +} + + +/* Fixes for fixed navbar --------------------------*/ + +.contents h1, .contents h2, .contents h3, .contents h4 { + padding-top: 60px; + margin-top: -40px; +} + +/* Static header placement on mobile devices */ +@media (max-width: 767px) { + .navbar-fixed-top { + position: absolute; + } + .navbar { + padding: 0; + } +} + + +/* Sidebar --------------------------*/ + +#sidebar { + margin-top: 30px; +} +#sidebar h2 { + font-size: 1.5em; + margin-top: 1em; +} + +#sidebar h2:first-child { + margin-top: 0; +} + +#sidebar .list-unstyled li { + margin-bottom: 0.5em; +} + +.orcid { + height: 16px; + vertical-align: middle; +} + +/* Reference index & topics ----------------------------------------------- */ + +.ref-index th {font-weight: normal;} + +.ref-index td {vertical-align: top;} +.ref-index .alias {width: 40%;} +.ref-index .title {width: 60%;} + +.ref-index .alias {width: 40%;} +.ref-index .title {width: 60%;} + +.ref-arguments th {text-align: right; padding-right: 10px;} +.ref-arguments th, .ref-arguments td {vertical-align: top;} +.ref-arguments .name {width: 20%;} +.ref-arguments .desc {width: 80%;} + +/* Nice scrolling for wide elements --------------------------------------- */ + +table { + display: block; + overflow: auto; +} + +/* Syntax highlighting ---------------------------------------------------- */ + +pre { + word-wrap: normal; + word-break: normal; + border: 1px solid #eee; +} + +pre, code { + background-color: #f8f8f8; + color: #333; +} + +pre code { + overflow: auto; + word-wrap: normal; + white-space: pre; +} + +pre .img { + margin: 5px 0; +} + +pre .img img { + background-color: #fff; + display: block; + height: auto; +} + +code a, pre a { + color: #375f84; +} + +a.sourceLine:hover { + text-decoration: none; +} + +.fl {color: #1514b5;} +.fu {color: #000000;} /* function */ +.ch,.st {color: #036a07;} /* string */ +.kw {color: #264D66;} /* keyword */ +.co {color: #888888;} /* comment */ + +.message { color: black; font-weight: bolder;} +.error { color: orange; font-weight: bolder;} +.warning { color: #6A0366; font-weight: bolder;} + +/* Clipboard --------------------------*/ + +.hasCopyButton { + position: relative; +} + +.btn-copy-ex { + position: absolute; + right: 0; + top: 0; + visibility: hidden; +} + +.hasCopyButton:hover button.btn-copy-ex { + visibility: visible; +} diff --git a/docs/pkgdown.js b/docs/pkgdown.js new file mode 100644 index 0000000..362b060 --- /dev/null +++ b/docs/pkgdown.js @@ -0,0 +1,101 @@ +$(function() { + + $("#sidebar") + .stick_in_parent({offset_top: 40}) + .on('sticky_kit:bottom', function(e) { + $(this).parent().css('position', 'static'); + }) + .on('sticky_kit:unbottom', function(e) { + $(this).parent().css('position', 'relative'); + }); + + $('body').scrollspy({ + target: '#sidebar', + offset: 60 + }); + + $('[data-toggle="tooltip"]').tooltip(); + + var cur_path = paths(location.pathname); + $("#navbar ul li a").each(function(index, value) { + if (value.text == "Home") + return; + if (value.getAttribute("href") === "#") + return; + + var path = paths(value.pathname); + if (is_prefix(cur_path, path)) { + // Add class to parent
  • , and enclosing
  • if in dropdown + var menu_anchor = $(value); + menu_anchor.parent().addClass("active"); + menu_anchor.closest("li.dropdown").addClass("active"); + } + }); +}); + +function paths(pathname) { + var pieces = pathname.split("/"); + pieces.shift(); // always starts with / + + var end = pieces[pieces.length - 1]; + if (end === "index.html" || end === "") + pieces.pop(); + return(pieces); +} + +function is_prefix(needle, haystack) { + if (needle.length > haystack.lengh) + return(false); + + // Special case for length-0 haystack, since for loop won't run + if (haystack.length === 0) { + return(needle.length === 0); + } + + for (var i = 0; i < haystack.length; i++) { + if (needle[i] != haystack[i]) + return(false); + } + + return(true); +} + +/* Clipboard --------------------------*/ + +function changeTooltipMessage(element, msg) { + var tooltipOriginalTitle=element.getAttribute('data-original-title'); + element.setAttribute('data-original-title', msg); + $(element).tooltip('show'); + element.setAttribute('data-original-title', tooltipOriginalTitle); +} + +if(Clipboard.isSupported()) { + $(document).ready(function() { + var copyButton = ""; + + $(".examples").addClass("hasCopyButton"); + + // Insert copy buttons: + $(copyButton).prependTo(".hasCopyButton"); + + // Initialize tooltips: + $('.btn-copy-ex').tooltip({container: 'body'}); + + // Initialize clipboard: + var clipboardBtnCopies = new Clipboard('[data-clipboard-copy]', { + text: function(trigger) { + return trigger.parentNode.textContent; + } + }); + + clipboardBtnCopies.on('success', function(e) { + changeTooltipMessage(e.trigger, 'Copied!'); + e.clearSelection(); + }); + + clipboardBtnCopies.on('error', function() { + changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy'); + }); + }); +} + diff --git a/docs/pkgdown.yml b/docs/pkgdown.yml new file mode 100644 index 0000000..aa3cd62 --- /dev/null +++ b/docs/pkgdown.yml @@ -0,0 +1,5 @@ +pandoc: 2.1.2 +pkgdown: 0.1.0.9000 +pkgdown_sha: 5e4825875751c009444c56ce43d06324ec53e910 +articles: [] + diff --git a/docs/reference/eval_recursion.html b/docs/reference/eval_recursion.html new file mode 100644 index 0000000..cebb879 --- /dev/null +++ b/docs/reference/eval_recursion.html @@ -0,0 +1,154 @@ + + + + + + + + +Evaluate an entire dynprog recursion. — eval_recursion • dynprog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    + +
    +
    + + + +

    This function takes the ranges and recursions of a specification and +evaluate the dynprog expression, returning a filled out dynamic programming +table.

    + + +
    eval_recursion(ranges, recursions)
    + +

    Arguments

    + + + + + + + + + + +
    ranges

    The ranges specification

    recursions

    The recursions specification

    + +

    Value

    + +

    The filled out dynamic programming table

    + + +
    + +
    + +
    + + +
    +

    Site built with pkgdown.

    +
    + +
    +
    + + + + diff --git a/man/figures/README-pressure-1.png b/docs/reference/figures/README-pressure-1.png similarity index 100% rename from man/figures/README-pressure-1.png rename to docs/reference/figures/README-pressure-1.png diff --git a/docs/reference/get_table_name.html b/docs/reference/get_table_name.html new file mode 100644 index 0000000..b3186c4 --- /dev/null +++ b/docs/reference/get_table_name.html @@ -0,0 +1,150 @@ + + + + + + + + +Extract the table name from a pattern. — get_table_name • dynprog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    + +
    +
    + + + +

    We generally assume that patterns are on the form table[exprs] +where table is the name of the dynamic programming table. This +function extract that name.

    + + +
    get_table_name(patterns)
    + +

    Arguments

    + + + + + + +
    patterns

    The patterns used in the recursion.

    + +

    Value

    + +

    The table part of the pattern.

    + + +
    + +
    + +
    + + +
    +

    Site built with pkgdown.

    +
    + +
    +
    + + + + diff --git a/docs/reference/grapes-where-grapes.html b/docs/reference/grapes-where-grapes.html new file mode 100644 index 0000000..c17ec96 --- /dev/null +++ b/docs/reference/grapes-where-grapes.html @@ -0,0 +1,153 @@ + + + + + + + + +Connects a recursion with sequences it should recurse over. — %where% • dynprog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    + +
    +
    + + + +

    This function parses a dynamic programming recursion expression and evaluates +it, returning the table that the recursions specify.

    + + +
    recursion %where% ranges
    + +

    Arguments

    + + + + + + + + + + +
    recursion

    Specification of the dynamic programming recursion.

    ranges

    Specification of the index-ranges the recursion should +compute values over.

    + +

    Value

    + +

    A filled out dynamic programming table.

    + + +
    + +
    + +
    + + +
    +

    Site built with pkgdown.

    +
    + +
    +
    + + + + diff --git a/docs/reference/index.html b/docs/reference/index.html new file mode 100644 index 0000000..69088ca --- /dev/null +++ b/docs/reference/index.html @@ -0,0 +1,199 @@ + + + + + + + + +Function reference • dynprog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    + +
    +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    All functions

    +

    +
    +

    eval_recursion()

    +

    Evaluate an entire dynprog recursion.

    +

    get_table_name()

    +

    Extract the table name from a pattern.

    +

    `%where%`()

    +

    Connects a recursion with sequences it should recurse over.

    +

    make_condition_checks()

    +

    Translate condition expressions into calls that test them.

    +

    make_pattern_match()

    +

    Translate a pattern into a predicate that checks the pattern.

    +

    make_pattern_tests()

    +

    Make pattern tests for all patterns.

    +

    make_recursion_case()

    +

    Construct a test for a case in the recursion

    +

    make_update_expr()

    +

    String together the case if-statements of a recursion.

    +

    parse_ranges()

    +

    Parser for the ranges part of a specification.

    +

    parse_recursion()

    +

    Parser for the recursion part of a specification.

    +
    +
    + + +
    + +
    + + +
    +

    Site built with pkgdown.

    +
    + +
    +
    + + + + diff --git a/docs/reference/make_condition_checks.html b/docs/reference/make_condition_checks.html new file mode 100644 index 0000000..c5e8ddb --- /dev/null +++ b/docs/reference/make_condition_checks.html @@ -0,0 +1,160 @@ + + + + + + + + +Translate condition expressions into calls that test them. — make_condition_checks • dynprog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    + +
    +
    + + + +

    Takes the full dynprog expression and construct a list of condition +tests for each component of the recursion.

    + + +
    make_condition_checks(ranges, patterns, conditions, recursions)
    + +

    Arguments

    + + + + + + + + + + + + + + + + + + +
    ranges

    The ranges specifications

    patterns

    The patterns specifications

    conditions

    The conditions specifications

    recursions

    The recursions specification

    + +

    Value

    + +

    A list of calls, one per recursion, for testing conditions.

    + + +
    + +
    + +
    + + +
    +

    Site built with pkgdown.

    +
    + +
    +
    + + + + diff --git a/docs/reference/make_pattern_match.html b/docs/reference/make_pattern_match.html new file mode 100644 index 0000000..8638896 --- /dev/null +++ b/docs/reference/make_pattern_match.html @@ -0,0 +1,152 @@ + + + + + + + + +Translate a pattern into a predicate that checks the pattern. — make_pattern_match • dynprog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    + +
    +
    + + + +

    Takes a pattern from the DSL and make a comparison of the +pattern specification against range variables.

    + + +
    make_pattern_match(pattern, range_vars)
    + +

    Arguments

    + + + + + + + + + + +
    pattern

    An expression on the form table[index-list]

    range_vars

    A list of the variables used in the ranges.

    + +

    Value

    + +

    An expression that tests pattern against range_vars.

    + + +
    + +
    + +
    + + +
    +

    Site built with pkgdown.

    +
    + +
    +
    + + + + diff --git a/docs/reference/make_pattern_tests.html b/docs/reference/make_pattern_tests.html new file mode 100644 index 0000000..5c32abd --- /dev/null +++ b/docs/reference/make_pattern_tests.html @@ -0,0 +1,152 @@ + + + + + + + + +Make pattern tests for all patterns. — make_pattern_tests • dynprog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    + +
    +
    + + + +

    This function calls make_pattern_match() for each pattern in patterns +and return a list of all the pattern test expressions.

    + + +
    make_pattern_tests(patterns, range_vars)
    + +

    Arguments

    + + + + + + + + + + +
    patterns

    A list of the patterns used in a recursion.

    range_vars

    The variables used in the ranges.

    + +

    Value

    + +

    A list of pattern check expressions.

    + + +
    + +
    + +
    + + +
    +

    Site built with pkgdown.

    +
    + +
    +
    + + + + diff --git a/docs/reference/make_recursion_case.html b/docs/reference/make_recursion_case.html new file mode 100644 index 0000000..846c9b3 --- /dev/null +++ b/docs/reference/make_recursion_case.html @@ -0,0 +1,156 @@ + + + + + + + + +Construct a test for a case in the recursion — make_recursion_case • dynprog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    + +
    +
    + + + +

    This function creates an if-statement for testing if a case can be +applied.

    + + +
    make_recursion_case(test_expr, value_expr, continue)
    + +

    Arguments

    + + + + + + + + + + + + + + +
    test_expr

    The expression that must be true for the case to be applied

    value_expr

    The value to compute if the test is true

    continue

    The next case to check if this one isn't true

    + +

    Value

    + +

    An if-statement for checking and potentially evaluating one case.

    + + +
    + +
    + +
    + + +
    +

    Site built with pkgdown.

    +
    + +
    +
    + + + + diff --git a/docs/reference/make_update_expr.html b/docs/reference/make_update_expr.html new file mode 100644 index 0000000..abd8651 --- /dev/null +++ b/docs/reference/make_update_expr.html @@ -0,0 +1,158 @@ + + + + + + + + +String together the case <code>if</code>-statements of a recursion. — make_update_expr • dynprog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    + +
    +
    + + + +

    String together the case if-statements of a recursion.

    + + +
    make_update_expr(ranges, patterns, conditions, recursions)
    + +

    Arguments

    + + + + + + + + + + + + + + + + + + +
    ranges

    The ranges specification

    patterns

    The patterns specification

    conditions

    The conditions specifications

    recursions

    The recursions specification

    + +

    Value

    + +

    A series of if-else-statements for evaluating a recursion.

    + + +
    + +
    + +
    + + +
    +

    Site built with pkgdown.

    +
    + +
    +
    + + + + diff --git a/docs/reference/parse_ranges.html b/docs/reference/parse_ranges.html new file mode 100644 index 0000000..c82d7b6 --- /dev/null +++ b/docs/reference/parse_ranges.html @@ -0,0 +1,152 @@ + + + + + + + + +Parser for the ranges part of a specification. — parse_ranges • dynprog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    + +
    +
    + + + +

    Parses the ranges and return a list of index +variables an the values they should iterate over. The ranges are returned as +a list with the range variables as its names and the range values as the +list components.

    + + +
    parse_ranges(ranges)
    + +

    Arguments

    + + + + + + +
    ranges

    The quosure wrapping the input to the specification.

    + +

    Value

    + +

    A parsed specification for ranges.

    + + +
    + +
    + +
    + + +
    +

    Site built with pkgdown.

    +
    + +
    +
    + + + + diff --git a/docs/reference/parse_recursion.html b/docs/reference/parse_recursion.html new file mode 100644 index 0000000..bbe3c47 --- /dev/null +++ b/docs/reference/parse_recursion.html @@ -0,0 +1,158 @@ + + + + + + + + +Parser for the recursion part of a specification. — parse_recursion • dynprog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    + +
    +
    + + + +

    Parse the recursion part of an expressions.

    + + +
    parse_recursion(recursion)
    + +

    Arguments

    + + + + + + +
    recursion

    The quosure wrapping the recursion of the specification.

    + +

    Value

    + +

    A parsed specification for recursions.

    + +

    Details

    + +

    The parser return a list with the following components:

      +
    • recursion_env: The environment in which expressions should be +evaluated.

    • +
    • patterns: A list of patterns, one per recursion case.

    • +
    • conditions: A list of conditions, one per recursion case.

    • +
    • recursions: A list of expressions, one per recursion case.

    • +
    + + +
    + +
    + + +
    + + + + diff --git a/man/eval_recursion.Rd b/man/eval_recursion.Rd index b17a6ca..64a9ebb 100644 --- a/man/eval_recursion.Rd +++ b/man/eval_recursion.Rd @@ -7,7 +7,7 @@ eval_recursion(ranges, recursions) } \arguments{ -\item{ranges}{The ranges specificatoin} +\item{ranges}{The ranges specification} \item{recursions}{The recursions specification} } diff --git a/man/grapes-where-grapes.Rd b/man/grapes-where-grapes.Rd index 0a13262..b88d434 100644 --- a/man/grapes-where-grapes.Rd +++ b/man/grapes-where-grapes.Rd @@ -19,3 +19,32 @@ A filled out dynamic programming table. This function parses a dynamic programming recursion expression and evaluates it, returning the table that the recursions specify. } +\examples{ + +# Fibonnaci numbers +fib <- { + F[n] <- 1 ? n <= 2 + F[n] <- F[n-1] + F[n-2] +} \%where\% { + n <- 1:10 +} +fib + +# Edit distance +x <- c("a", "b", "c") +y <- c("a", "b", "b", "c") +edit <- { + E[1,j] <- j - 1 + E[i,1] <- i - 1 + E[i,j] <- min( + E[i - 1,j] + 1, + E[i,j - 1] + 1, + E[i - 1,j - 1] + (x[i - 1] != y[j - 1]) + ) +} \%where\% { + i <- 1:(length(x) + 1) + j <- 1:(length(y) + 1) +} +edit + +} diff --git a/man/make_condition_checks.Rd b/man/make_condition_checks.Rd index d631588..549a62e 100644 --- a/man/make_condition_checks.Rd +++ b/man/make_condition_checks.Rd @@ -16,7 +16,7 @@ make_condition_checks(ranges, patterns, conditions, recursions) \item{recursions}{The recursions specification} } \value{ -A list of calls, one per recurision, for testing conditions. +A list of calls, one per recursion, for testing conditions. } \description{ Takes the full dynprog expression and construct a list of condition diff --git a/man/parse_recursion.Rd b/man/parse_recursion.Rd index 6ced47c..6c6d656 100644 --- a/man/parse_recursion.Rd +++ b/man/parse_recursion.Rd @@ -20,7 +20,7 @@ The parser return a list with the following components: \itemize{ \item \strong{recursion_env:} The environment in which expressions should be evaluated. -\item \strong{partterns:} A list of patterns, one per recursion case. +\item \strong{patterns:} A list of patterns, one per recursion case. \item \strong{conditions:} A list of conditions, one per recursion case. \item \strong{recursions:} A list of expressions, one per recursion case. } diff --git a/tests/testthat/test-dsl.R b/tests/testthat/test-dsl.R index 6abd507..5a717b6 100644 --- a/tests/testthat/test-dsl.R +++ b/tests/testthat/test-dsl.R @@ -15,6 +15,30 @@ test_that("we can evaluate `fact`", { expect_equal(as.vector(fact), c(1, 2, 6, 24, 120, 720, 5040, 40320)) }) +test_that("we can evaluate `Fibonnaci`", { + fib1 <- { + F[1] <- 1 + F[2] <- 1 + F[n] <- F[n - 1] + F[n - 2] + } %where% { + n <- 1:10 + } + fib2 <- { + F[n] <- F[n-1] + F[n-2] ? n > 2 + F[n] <- 1 + } %where% { + n <- 1:10 + } + fib3 <- { + F[n] <- 1 ? n <= 2 + F[n] <- F[n-1] + F[n-2] + } %where% { + n <- 1:10 + } + + expect_equal(fib1, fib2) + expect_equal(fib1, fib3) +}) test_that("we can evaluate `edit`", {