├── .Rbuildignore ├── .github ├── .gitignore └── workflows │ ├── R-CMD-check.yaml │ └── pkgdown.yaml ├── .gitignore ├── DESCRIPTION ├── INSTALL ├── LICENSE ├── NAMESPACE ├── NEWS.md ├── R ├── bench.R ├── boin.R ├── ccd.R ├── cpe.R ├── crm.R ├── data.R ├── dtp.R ├── dutycycle.R ├── enhance.R ├── exact.R ├── extendr-wrappers.R ├── hyperprior.R ├── mclapply.R ├── precautionary-package.R ├── simulate_trials.R ├── sysdata.rda ├── three3.R └── toxicity_generators.R ├── README.md ├── configure ├── data └── viola_dtp.rda ├── demo ├── 00Index └── EscRisk.R ├── docs ├── 404.html ├── LICENSE-text.html ├── apple-touch-icon-120x120.png ├── apple-touch-icon-152x152.png ├── apple-touch-icon-180x180.png ├── apple-touch-icon-60x60.png ├── apple-touch-icon-76x76.png ├── apple-touch-icon.png ├── articles │ ├── DTP-vs-Korn94.html │ ├── DTP-vs-Korn94_files │ │ ├── DiagrammeR-styles-0.2 │ │ │ └── styles.css │ │ ├── accessible-code-block-0.0.1 │ │ │ └── empty-anchor.js │ │ ├── grViz-binding-1.0.6.1 │ │ │ └── grViz.js │ │ ├── header-attrs-2.7 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.8 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.9 │ │ │ └── header-attrs.js │ │ ├── htmlwidgets-1.5.3 │ │ │ └── htmlwidgets.js │ │ ├── htmlwidgets-1.5.4 │ │ │ └── htmlwidgets.js │ │ └── viz-1.8.2 │ │ │ └── viz.js │ ├── FDA-proactive.html │ ├── FDA-proactive_files │ │ ├── accessible-code-block-0.0.1 │ │ │ └── empty-anchor.js │ │ ├── figure-html │ │ │ └── hyperprior-1.png │ │ ├── header-attrs-2.7 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.8 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.9 │ │ │ └── header-attrs.js │ │ ├── kePrint-0.0.1 │ │ │ └── kePrint.js │ │ └── lightable-0.0.1 │ │ │ └── lightable.css │ ├── Intro.html │ ├── Intro_files │ │ ├── accessible-code-block-0.0.1 │ │ │ └── empty-anchor.js │ │ ├── figure-html │ │ │ ├── Raleigh-distribution-1.png │ │ │ ├── hyperprior-1.png │ │ │ └── unnamed-chunk-3-1.png │ │ ├── header-attrs-2.7 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.8 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.9 │ │ │ └── header-attrs.js │ │ ├── kePrint-0.0.1 │ │ │ └── kePrint.js │ │ └── lightable-0.0.1 │ │ │ └── lightable.css │ ├── MCSE-Free.html │ ├── MCSE-Free_files │ │ ├── accessible-code-block-0.0.1 │ │ │ └── empty-anchor.js │ │ ├── figure-html │ │ │ └── kraken-plot-1.png │ │ ├── header-attrs-2.7 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.8 │ │ │ └── header-attrs.js │ │ ├── header-attrs-2.9 │ │ │ └── header-attrs.js │ │ ├── kePrint-0.0.1 │ │ │ └── kePrint.js │ │ └── lightable-0.0.1 │ │ │ └── lightable.css │ ├── Safety-Schematic-via-CPE.html │ ├── Safety-Schematic-via-CPE_files │ │ ├── accessible-code-block-0.0.1 │ │ │ └── empty-anchor.js │ │ ├── figure-html │ │ │ ├── VIOLA-dose-scaling-1.png │ │ │ ├── contourplot-1.png │ │ │ ├── fatalities-vs-kappa-1.png │ │ │ ├── skeleton-as-expectation-1.png │ │ │ └── skeleton-log-match-1.png │ │ └── header-attrs-2.9 │ │ │ └── header-attrs.js │ └── index.html ├── authors.html ├── bootstrap-toc.css ├── bootstrap-toc.js ├── card.png ├── docsearch.css ├── docsearch.js ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── index.html ├── link.svg ├── logo.svg ├── news │ └── index.html ├── pkgdown.css ├── pkgdown.js ├── pkgdown.yml ├── reference │ ├── Boin-class.html │ ├── Ccd-class.html │ ├── Cpe-class.html │ ├── Cpe3_3-class.html │ ├── Crm-class.html │ ├── HyperMTDi-class.html │ ├── Rplot001.png │ ├── applied_crm.html │ ├── as.data.table.exact.html │ ├── as.data.table.precautionary.html │ ├── calculate_dtps.html │ ├── cohorts_of_n.html │ ├── crm.html │ ├── crmh.html │ ├── crmh_xo.html │ ├── exact.html │ ├── extend.html │ ├── figures │ │ ├── card.png │ │ └── logo.svg │ ├── format.safetytab.html │ ├── hyper_mtdi_lognormal-class.html │ ├── index.html │ ├── mtdi_lognormal-class.html │ ├── ordinalizer.html │ ├── phase1_sim.html │ ├── plan.html │ ├── plot-mtdi_distribution-ANY-method.html │ ├── plot-mtdi_generator-ANY-method.html │ ├── plot_dutycycle.html │ ├── precautionary-package.html │ ├── print.exact.html │ ├── print.hyper.html │ ├── print.precautionary.html │ ├── safety_kable.html │ ├── simulate_trials.html │ ├── simulation_function.u_i.html │ ├── stop_for_excess_toxicity_empiric.html │ ├── summary.exact.html │ ├── summary.precautionary.html │ ├── test_draw_samples.html │ └── viola_dtp.html └── sitemap.xml ├── exec ├── Makefile ├── T2.tab ├── T3.tab ├── T4.tab ├── T5.tab ├── T6.tab ├── T7.tab ├── T8.tab ├── esc.pl ├── make_sysdata_TUb.R ├── prolog │ ├── BOIN25-2-6-24.tab │ ├── BOIN25-3-6-24.tab │ ├── BOIN25-4-6-24.tab │ ├── BOIN25-4-9-24.tab │ ├── BOIN_get.oc.R │ ├── aliquots.pl │ ├── benchmarking.pl │ ├── boin.R │ ├── boin.pl │ ├── ccd.pl │ ├── ccd_check.pl │ ├── designs.pl │ ├── dsl.pl │ ├── factorial.pl │ ├── inconceivable.pl │ ├── monot.pl │ ├── qbeta.pl │ ├── retro.pl │ ├── rolling.pl │ ├── subsumption.pl │ ├── swi.pl │ ├── tally.pl │ ├── testD2 │ └── three3.pl ├── scryer.pl └── sicstus.pl ├── inst ├── WORDLIST ├── shiny-apps │ └── EscRisk │ │ ├── app.R │ │ └── www │ │ ├── events.js │ │ ├── help.js │ │ ├── intro.js │ │ ├── introjs.css │ │ └── tweaks.css └── testdata │ ├── BOIN25-3-6-24.tab │ └── BOIN25-4-6-24.tab ├── man ├── Boin-class.Rd ├── Ccd-class.Rd ├── Cpe-class.Rd ├── Cpe3_3-class.Rd ├── Crm-class.Rd ├── HyperMTDi-class.Rd ├── as.data.table.exact.Rd ├── as.data.table.precautionary.Rd ├── cohorts_of_n.Rd ├── crm.Rd ├── crmh.Rd ├── crmh_xo.Rd ├── exact.Rd ├── extend.Rd ├── figures │ └── logo.svg ├── format.safetytab.Rd ├── hyper_mtdi_lognormal-class.Rd ├── mtdi_lognormal-class.Rd ├── ordinalizer.Rd ├── phase1_sim.Rd ├── plan.Rd ├── plot-mtdi_distribution-ANY-method.Rd ├── plot-mtdi_generator-ANY-method.Rd ├── plot_dutycycle.Rd ├── precautionary-package.Rd ├── print.exact.Rd ├── print.hyper.Rd ├── print.precautionary.Rd ├── safety_kable.Rd ├── simulate_trials.Rd ├── simulation_function.u_i.Rd ├── stop_for_excess_toxicity_empiric.Rd ├── summary.exact.Rd ├── summary.precautionary.Rd ├── test_draw_samples.Rd └── viola_dtp.Rd ├── pkgdown └── _pkgdown.yml ├── precautionary.Rproj ├── src ├── .gitignore ├── Makevars ├── Makevars.win ├── entrypoint.c └── rust │ ├── Cargo.toml │ └── src │ └── lib.rs ├── tests ├── manual │ ├── crm-numerics.R │ ├── pending.R │ └── speed.R ├── testthat.R └── testthat │ ├── test-boin.R │ ├── test-crm.R │ ├── test-enhance.R │ ├── test-exact.R │ ├── test-fractionation.R │ └── test-viola-dtp.R └── vignettes ├── DTP-vs-Korn94.Rmd ├── FDA-proactive.Rmd ├── Intro.Rmd ├── MCSE-Free.Rmd ├── Safety-Schematic-via-CPE.Rmd └── precautionary-package.bib /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^TODO$ 4 | ^cran-comments.md 5 | ^publicity 6 | ^inst/shiny-apps/.*/rsconnect 7 | ^vignettes/DTP-vs-Korn94.* 8 | ^exec/prolog/.* 9 | ^exec/T[5-9].tab 10 | ^tests/manual 11 | ^Rprof.out 12 | ^doc$ 13 | ^Meta$ 14 | ^_pkgdown\.yml$ 15 | ^docs$ 16 | ^pkgdown$ 17 | ^\.github$ 18 | ^CRAN-RELEASE$ 19 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # NOTE: This workflow is overkill for most R packages 2 | # check-standard.yaml is likely a better choice 3 | # usethis::use_github_action("check-standard") will install it. 4 | # 5 | # For help debugging build failures open an issue on the RStudio community with the 'github-actions' tag. 6 | # https://community.rstudio.com/new-topic?category=Package%20development&tags=github-actions 7 | on: 8 | push: 9 | branches: 10 | - main 11 | - cran 12 | pull_request: 13 | branches: 14 | - main 15 | - cran 16 | 17 | name: R-CMD-check 18 | 19 | jobs: 20 | R-CMD-check: 21 | runs-on: ${{ matrix.config.os }} 22 | 23 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 24 | 25 | strategy: 26 | fail-fast: false 27 | matrix: 28 | config: 29 | - {os: macOS-latest, r: 'release'} 30 | - {os: ubuntu-18.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest"} 31 | #- {os: windows-latest, r: 'release'} 32 | - {os: ubuntu-18.04, r: 'devel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest", http-user-agent: "R/4.1.0 (ubuntu-18.04) R (4.1.0 x86_64-pc-linux-gnu x86_64 linux-gnu) on GitHub Actions" } 33 | 34 | env: 35 | RSPM: ${{ matrix.config.rspm }} 36 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 37 | 38 | steps: 39 | - uses: actions/checkout@v2 40 | 41 | - uses: r-lib/actions/setup-r@v1 42 | id: install-r 43 | with: 44 | r-version: ${{ matrix.config.r }} 45 | http-user-agent: ${{ matrix.config.http-user-agent }} 46 | 47 | - uses: r-lib/actions/setup-pandoc@v1 48 | 49 | - name: Install pak and query dependencies 50 | run: | 51 | install.packages("pak", repos = "https://r-lib.github.io/p/pak/dev/") 52 | saveRDS(pak::pkg_deps("local::.", dependencies = TRUE), ".github/r-depends.rds") 53 | shell: Rscript {0} 54 | 55 | - name: Restore R package cache 56 | uses: actions/cache@v2 57 | with: 58 | path: | 59 | ${{ env.R_LIBS_USER }}/* 60 | !${{ env.R_LIBS_USER }}/pak 61 | key: ${{ matrix.config.os }}-${{ steps.install-r.outputs.installed-r-version }}-1-${{ hashFiles('.github/r-depends.rds') }} 62 | restore-keys: ${{ matrix.config.os }}-${{ steps.install-r.outputs.installed-r-version }}-1- 63 | 64 | - name: Avoid Rust error[E0463] on Windows; see https://stackoverflow.com/q/66252428/3338147 65 | if: runner.os == 'Windows' 66 | run: rustup target add x86_64-pc-windows-gnu; rustup target add i686-pc-windows-gnu 67 | shell: bash 68 | 69 | - name: Install system dependencies 70 | if: runner.os == 'Linux' 71 | run: | 72 | pak::local_system_requirements(execute = TRUE) 73 | pak::pkg_system_requirements("rcmdcheck", execute = TRUE) 74 | shell: Rscript {0} 75 | 76 | - name: Install dependencies 77 | run: | 78 | pak::local_install_dev_deps(upgrade = TRUE) 79 | pak::pkg_install("rcmdcheck") 80 | shell: Rscript {0} 81 | 82 | - name: Session info 83 | run: | 84 | options(width = 100) 85 | pkgs <- installed.packages()[, "Package"] 86 | sessioninfo::session_info(pkgs, include_base = TRUE) 87 | shell: Rscript {0} 88 | 89 | - name: Check 90 | env: 91 | _R_CHECK_CRAN_INCOMING_: false 92 | run: | 93 | options(crayon.enabled = TRUE) 94 | rcmdcheck::rcmdcheck(args = c("--no-manual", "--as-cran"), error_on = "warning", check_dir = "check") 95 | shell: Rscript {0} 96 | 97 | - name: Show testthat output 98 | if: always() 99 | run: find check -name 'testthat.Rout*' -exec cat '{}' \; || true 100 | shell: bash 101 | 102 | - name: Upload check results 103 | if: failure() 104 | uses: actions/upload-artifact@main 105 | with: 106 | name: ${{ matrix.config.os }}-r${{ matrix.config.r }}-results 107 | path: check 108 | 109 | - name: Don't use tar from old Rtools to store the cache 110 | if: ${{ runner.os == 'Windows' && startsWith(steps.install-r.outputs.installed-r-version, '3.6' ) }} 111 | shell: bash 112 | run: echo "C:/Program Files/Git/usr/bin" >> $GITHUB_PATH 113 | -------------------------------------------------------------------------------- /.github/workflows/pkgdown.yaml: -------------------------------------------------------------------------------- 1 | name: pkgdown 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | pkgdown: 10 | runs-on: macOS-latest 11 | env: 12 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - uses: r-lib/actions/setup-r@v1 17 | 18 | - uses: r-lib/actions/setup-pandoc@v1 19 | 20 | - name: Query dependencies 21 | run: | 22 | install.packages('remotes') 23 | saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2) 24 | writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version") 25 | shell: Rscript {0} 26 | 27 | - name: Restore R package cache 28 | uses: actions/cache@v2 29 | with: 30 | path: ${{ env.R_LIBS_USER }} 31 | key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }} 32 | restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1- 33 | 34 | - name: Install dependencies 35 | run: | 36 | remotes::install_deps(dependencies = TRUE) 37 | install.packages("pkgdown", type = "binary") 38 | shell: Rscript {0} 39 | 40 | - name: Install package 41 | run: R CMD INSTALL . 42 | 43 | - name: Deploy package 44 | run: | 45 | git config --local user.email "actions@github.com" 46 | git config --local user.name "GitHub Actions" 47 | Rscript -e 'pkgdown::deploy_to_branch(new_process = FALSE)' 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .RData 3 | .Rhistory 4 | vignettes/*.html 5 | vignettes/packages.bib 6 | doc 7 | Meta 8 | pkgdown/favicon 9 | .DS_Store 10 | .Rdata 11 | .Rhistory 12 | pkgdown/ 13 | # I believe pkgdown::build_site() errs in copying logo.svg to this 'png' 14 | docs/package-logo.png 15 | *~ 16 | /doc/ 17 | /Meta/ 18 | .ediprolog-temp 19 | Rprof.out 20 | publicity/ 21 | rsconnect/ 22 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: precautionary 2 | Type: Package 3 | Title: Safety Diagnostics for Dose-Escalation Trial Designs 4 | Version: 0.2.6-1 5 | Date: 2021-08-14 6 | Authors@R: c(person("David C.", "Norris" 7 | , role = c("aut", "cre", "cph") 8 | , email = "david@precisionmethods.guru" 9 | , comment = c(ORCID = "0000-0001-9593-6343") 10 | ), 11 | person("Markus", "Triska" 12 | , role = "ctb" 13 | , email = "triska@metalevel.at" 14 | ) 15 | ) 16 | Maintainer: David C. Norris 17 | Depends: 18 | magrittr, 19 | escalation, 20 | data.table, 21 | R6, 22 | R (>= 4.0.0) 23 | Imports: methods, dplyr, rlang, stringr, knitr, kableExtra, microbenchmark, dfcrm, BOIN, 24 | parallelly, utils 25 | Suggests: 26 | dtpcrm, 27 | rmarkdown, 28 | bookdown, 29 | tufte, 30 | testthat, 31 | lattice, 32 | latticeExtra, 33 | shiny, 34 | shinyjs, 35 | shinyFeedback 36 | Description: Enhances various R packages that support the design and simulation 37 | of phase 1 dose-escalation trials, adding diagnostics to examine 38 | the safety characteristics of these designs in light of expected 39 | inter-individual variation in pharmacokinetics and pharmacodynamics. 40 | See Norris (2020b), "Retrospective analysis of a fatal dose-finding 41 | trial" and (2020c) "What Were They Thinking? 42 | Pharmacologic priors implicit in a choice of 3+3 dose-escalation design" 43 | . 44 | URL: https://github.com/dcnorris/precautionary 45 | License: MIT + file LICENSE 46 | Roxygen: list(markdown = TRUE) 47 | VignetteBuilder: knitr, rmarkdown 48 | Encoding: UTF-8 49 | NeedsCompilation: yes 50 | OS_type: unix 51 | SystemRequirements: Cargo (rustc package manager) 52 | RoxygenNote: 7.1.1 53 | Collate: 54 | 'bench.R' 55 | 'boin.R' 56 | 'ccd.R' 57 | 'cpe.R' 58 | 'crm.R' 59 | 'data.R' 60 | 'dtp.R' 61 | 'dutycycle.R' 62 | 'enhance.R' 63 | 'exact.R' 64 | 'extendr-wrappers.R' 65 | 'hyperprior.R' 66 | 'mclapply.R' 67 | 'precautionary-package.R' 68 | 'toxicity_generators.R' 69 | 'simulate_trials.R' 70 | 'three3.R' 71 | LazyData: true 72 | ByteCompile: true 73 | Config/testthat/edition: 3 74 | BugReports: https://github.com/dcnorris/precautionary/issues 75 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | ## Acknowlegment 2 | 3 | I've adapted these instructions from the INSTALL file of package [baseflow](https://CRAN.R-project.org/package=baseflow). 4 | 5 | ## Installation 6 | 7 | ### Requirements 8 | 9 | This package has been developed and tested on macOS (10.15 Catalina), using cross-platform languages (Rust and R) that should enable it to work on other platforms. Beginning with version 0.2-2, this package makes substantive use of parallel::mclapply, which does not actually parallelize computations on Windows due to that platform's lack of fork(). This will not affect correctness of results, only how long Windows users have to wait for them. 10 | 11 | For installing this package from source, the following are needed: 12 | 13 | * A building environmment such as is generally installed with R on Linux distributions. On Windows, **Rtools** (available [here](https://cran.r-project.org/bin/windows/Rtools/)). 14 | * **cargo** Rust compilation platform, version 1.42 or above. Detailed installation instructions are given below. 15 | 16 | ### Rust platform 17 | 18 | General instructions to install the Rust compilation platform are given on the website [RustUp](https://rustup.rs/). It can be installed without administrator privileges - you do not need to ask your local computer technician that does not know Rust. 19 | 20 | #### Prior notice: PATH environment variable modification 21 | 22 | By default, the Rust compilation plaform is installed in `$HOME/.cargo` on Unix platforms and `%USERPROFILE%/.cargo` on Windows. This directory is then added to the PATH environment variable for the user to be able to use the toolchain without refering to the installation directory. 23 | 24 | If you plan to use Rust for other purpose than installing `precautionary`, you may prefer to set the *modify PATH variable* to *yes*. But if you wish only to build and install *precautionary*, to avoid any side-effect of the installation, you may set this option to *no* as explained below. 25 | CRAN policy prohibits published R packages from altering the user environment or filesystem apart from the R session. 26 | 27 | #### Windows 28 | 29 | On Windows, download and launch the rustup-init.exe script (64 bits version is [here](https://win.rustup.rs/x86_64), 32 bits is [here](https://win.rustup.rs/i686)). In the command prompt window, choose the second option `Customize installation` and set configuration as below. 30 | 31 | ``` 32 | default host triple: i686-pc-windows-gnu 33 | default toolchain: stable 34 | profile: default 35 | modify PATH variable: no 36 | ``` 37 | 38 | Then, choose the first option `Proceed with installation`. 39 | 40 | On 64-bits Windows systems, you also need to install the x64 target. After installation, open a terminal and type: 41 | 42 | ``` 43 | %USERPROFILE%\cargo\.bin\rustup.exe target add x86_64-pc-windows-gnu 44 | ``` 45 | 46 | #### Unix systems (GNU/Linux and macOS) 47 | 48 | On GNU/Linux platforms and other Unix systems, launch the following command into a terminal: 49 | 50 | ``` 51 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh 52 | ``` 53 | Here again, chose the second option `Customize installation` and set configuration as below. 54 | 55 | For GNU/Linux 64 bits systems: 56 | 57 | ``` 58 | default host triple: x86_64-unknown-linux-gnu 59 | default toolchain: stable 60 | profile: default 61 | modify PATH variable: no 62 | ``` 63 | 64 | For GNU/Linux 32 bits systems: 65 | 66 | ``` 67 | default host triple: i686-unknown-linux-gnu 68 | default toolchain: stable 69 | profile: default 70 | modify PATH variable: no 71 | ``` 72 | 73 | For macOS with Intel x86-64 architecture: 74 | 75 | ``` 76 | default host triple: x86_64-apple-darwin 77 | default toolchain: stable 78 | profile: default 79 | modify PATH variable: no 80 | ``` 81 | 82 | For macOS with ARM64 architecture (Apple Silicon): 83 | 84 | ``` 85 | default host triple: aarch64-apple-darwin 86 | default toolchain: stable 87 | profile: default 88 | modify PATH variable: no 89 | ``` 90 | 91 | For other platforms, detailed information about Rust support can be found [here](https://doc.rust-lang.org/rustc/platform-support.html). 92 | 93 | After modifying configuration, choose option 1 `Proceed with installation`. 94 | 95 | ### Package compilation and installation 96 | 97 | Download the source package as a `.tar.gz` file. Start R and run the following command in the console, where `path_to_package` is the path of the downloaded `.tar.gz` file of the package. 98 | 99 | ``` 100 | install.packages("path_to_package", repos = NULL, type = "source") 101 | ``` 102 | 103 | On Windows, you can directly download the binary `.zip` file, and run the following command, where `path_to_binary_package` is the path of the downloaded `.zip` file of the package. 104 | 105 | ``` 106 | install.packages("path_to_binary_package", repos = NULL, type = "win.binary") 107 | ``` 108 | 109 | After installation, try to load package using command 110 | 111 | ``` 112 | library(precautionary) 113 | ``` 114 | 115 | ### Uninstalling Rust platform after installation 116 | 117 | To uninstall Rust toolchain after installing the package, use the following commands: 118 | 119 | On Windows: 120 | 121 | ``` 122 | %USERPROFILE%\cargo\.bin\rustup.exe self uninstall 123 | ``` 124 | 125 | On Unix-based systems (macOS and GNU/Linux): 126 | 127 | ``` 128 | ~/cargo/.bin/rustup self uninstall 129 | ``` 130 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2020,2021 2 | COPYRIGHT HOLDER: David C. Norris 3 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | S3method(as.data.table,exact) 4 | S3method(as.data.table,precautionary) 5 | S3method(dose_indices,default) 6 | S3method(extend,exact) 7 | S3method(extend,hyper) 8 | S3method(extend,precautionary) 9 | S3method(format,safetytab) 10 | S3method(print,safetytab) 11 | S3method(simulation_function,u_i) 12 | S3method(summary,exact) 13 | S3method(summary,precautionary) 14 | S3method(t,safetytab) 15 | export(Boin) 16 | export(Ccd) 17 | export(Cpe) 18 | export(Cpe3_3) 19 | export(Crm) 20 | export(HyperMTDi_lognormal) 21 | export(cohorts_of_n) 22 | export(crmh) 23 | export(crmh_xo) 24 | export(crmht) 25 | export(crmht2) 26 | export(exact) 27 | export(extend) 28 | export(hyper_mtdi_lognormal) 29 | export(mtdi_lognormal) 30 | export(plot_dutycycle) 31 | export(safety_kable) 32 | export(simulate_trials) 33 | export(stop_for_excess_toxicity_empiric) 34 | export(test_draw_samples) 35 | exportMethods(plot) 36 | exportMethods(simulate_trials) 37 | import(data.table) 38 | import(magrittr) 39 | import(methods) 40 | importFrom(BOIN,get.boundary) 41 | importFrom(BOIN,select.mtd) 42 | importFrom(R6,R6Class) 43 | importFrom(dfcrm,crmhlgt) 44 | importFrom(dfcrm,crmht2lgt) 45 | importFrom(dfcrm,crmhtlgt) 46 | importFrom(dfcrm,lcrm) 47 | importFrom(dfcrm,lcrmlgt) 48 | importFrom(dplyr,everything) 49 | importFrom(dplyr,mutate) 50 | importFrom(dplyr,rename_with) 51 | importFrom(dplyr,select) 52 | importFrom(escalation,continue) 53 | importFrom(escalation,dose_indices) 54 | importFrom(escalation,num_doses) 55 | importFrom(escalation,num_patients) 56 | importFrom(escalation,num_tox) 57 | importFrom(escalation,parse_phase1_outcomes) 58 | importFrom(escalation,prob_administer) 59 | importFrom(escalation,prob_recommend) 60 | importFrom(escalation,recommended_dose) 61 | importFrom(escalation,selector_factory) 62 | importFrom(escalation,simulate_trials) 63 | importFrom(escalation,simulation_function) 64 | importFrom(escalation,trial_duration) 65 | importFrom(graphics,abline) 66 | importFrom(graphics,axis) 67 | importFrom(graphics,lines) 68 | importFrom(graphics,mtext) 69 | importFrom(graphics,par) 70 | importFrom(graphics,plot.default) 71 | importFrom(kableExtra,add_header_above) 72 | importFrom(kableExtra,kable_styling) 73 | importFrom(knitr,kable) 74 | importFrom(magrittr,"%>%") 75 | importFrom(microbenchmark,microbenchmark) 76 | importFrom(rlang,.data) 77 | importFrom(stats,addmargins) 78 | importFrom(stats,aggregate) 79 | importFrom(stats,integrate) 80 | importFrom(stats,median) 81 | importFrom(stats,optimize) 82 | importFrom(stats,plnorm) 83 | importFrom(stats,pnorm) 84 | importFrom(stats,qlnorm) 85 | importFrom(stats,qnorm) 86 | importFrom(stats,rchisq) 87 | importFrom(stats,rexp) 88 | importFrom(stats,rlnorm) 89 | importFrom(stats,runif) 90 | importFrom(stats,sd) 91 | importFrom(stats,var) 92 | importFrom(stats,xtabs) 93 | importFrom(stringr,str_pad) 94 | importFrom(utils,getFromNamespace) 95 | importFrom(utils,setTxtProgressBar) 96 | importFrom(utils,tail) 97 | importFrom(utils,txtProgressBar) 98 | useDynLib(precautionary, .registration = TRUE) 99 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # precautionary 0.2.6-1 2 | 3 | ## Changes 4 | 5 | * Restored Windows build via passthru implementation of `precautionary:::mclapply` 6 | * Refactored non-portable Makevars one-liner `export CARGO_HOME = ...` 7 | * Added vignette on MCSE-Free CRM Performance & Safety Evaluation 8 | 9 | # precautionary 0.2.6 10 | 11 | ## Changes 12 | 13 | * EscRisk app displays CPE progress via 'odometer' 14 | * EscRisk app lets user set max enrollment in range 20:30 15 | * Restrict to OS_type: unix, as feasible CPE demands fork-based parallelism 16 | 17 | # precautionary 0.2.5 18 | 19 | ## Changes 20 | 21 | * Overhauled EscRisk shiny app to use CPE 22 | 23 | # precautionary 0.2.4 24 | 25 | ## Changes 26 | 27 | * Refined version numbering scheme to 0..- 28 | * Implemented CPE as R6 superclass 'Cpe' 29 | * Implemented Cumulative-Cohort Designs (CCDs) in 'Cpe' subclass 'Ccd' 30 | * Implemented BOIN design as 'Boin' subclass of 'Ccd' 31 | * Executable specification for CCD and BOIN in exec/prolog/ 32 | * Demoted package dtpcrm from a 'Depends' to a 'Suggests' 33 | 34 | # precautionary 0.2-3 35 | 36 | ## Changes 37 | 38 | * Parallelized Crm$trace_paths method 39 | * Added 'MCSE-Free' calibration vignette 40 | 41 | # precautionary 0.2-2 42 | 43 | ## Changes 44 | 45 | * Implements R6 class to wrap CRM functions, with caching to speed DTP 46 | * Implements faster versions of certain objective functions from package 'dtpcrm' 47 | * Explicitly integrate() over c(-Inf,Inf) in 'crm' function (as per documentation) 48 | * Implements faster version of dtpcrm::stop_for_excess_toxicity_empiric 49 | * Corrected overloaded use of 'C' variable in text of DTP vignette 50 | 51 | # precautionary 0.2-1 52 | 53 | ## Changes 54 | 55 | * Added vignette 'Generalized dose-escalation safety schematics via DTP' 56 | * Corrected a few typos 57 | 58 | # precautionary 0.2 59 | 60 | ## Changes 61 | 62 | * Added a Prolog program to exhaustively enumerate 3+3 trial outcomes 63 | 64 | # precautionary 0.1-5 65 | 66 | ## Changes 67 | 68 | * Accommodate new 'true_prob_eff' arg in escalation::simulate_trials 69 | 70 | # precautionary 0.1-4 71 | 72 | ## Changes 73 | 74 | * Added vignette for a regulatory application 75 | 76 | # precautionary 0.1-3 77 | 78 | ## Changes 79 | 80 | * Added the EscRisk shiny app, runnable by demo(EscRisk) 81 | 82 | # precautionary 0.1-2 83 | 84 | ## Changes 85 | 86 | * Simulations are now extensible, via extend.(precautionary|hyper) methods 87 | * No longer using or depending on distr6, eliminating object creation overhead 88 | * Hyper-simulations no longer have a superfluous 'K' (within-hyperprior-draw) dimension 89 | * Sim summary()'s $safety component has prepended class 'safetytab' 90 | * The format.safetytab() method shows significant digits in accordance with MCSEs 91 | 92 | # precautionary 0.1-1 93 | 94 | * First public release 95 | -------------------------------------------------------------------------------- /R/bench.R: -------------------------------------------------------------------------------- 1 | ## This seems to be converging on a reasonable generic pattern. 2 | ## The idea is to write an expression 'expr' that includes '...' 3 | ## which can be filled in using (most appropriately!) this very 4 | ## function's '...' argument!) 5 | #' @importFrom microbenchmark microbenchmark 6 | #' @importFrom stats median 7 | benchtab <- function(expr, ...) { 8 | ## In general, this function should evaluate with various 9 | ## substitutions as provided in the ... args. 10 | ## Perhaps the ... will consist of a small number (1--3) of 11 | ## arguments, each of which is given as a short vector of 12 | ## alternative values. The resulting performance comparison 13 | ## ought to tabulate the performance against the full outer 14 | ## product of the possible values. 15 | fun <- eval(substitute(function(...) expr)) 16 | perf <- CJ(..., sorted = FALSE) 17 | mb <- list() 18 | for (i in seq(nrow(perf))) { 19 | mb[[i]] <- microbenchmark(do.call(fun, perf[i, ])) 20 | } 21 | perf$milliseconds <- sapply(mb, function(.) median(.$time)/1e6) 22 | perf$evals.per.sec <- sapply(mb, function(.) mean(1e9/.$time)) 23 | perf 24 | } 25 | 26 | ## Make reporting of speedups simple and uniform 27 | speedup_message <- function(fast, slow, 28 | prefix = paste(substitute(fast), "vs", substitute(slow)), 29 | digits = 2) { 30 | speedup <- 31 | if (is(fast,'microbenchmark')) { 32 | mean(slow$time) / mean(fast$time) 33 | } else if (is(fast,'proc_time')) { 34 | slow['elapsed'] / fast['elapsed'] # unlike 'self.time', 'elapsed' is valid for mclapply 35 | } else { # unwise to assume? 36 | slow[1] / fast[1] 37 | } 38 | message(prefix, " speedup: ", format(speedup, digits = digits), "x") 39 | } 40 | -------------------------------------------------------------------------------- /R/boin.R: -------------------------------------------------------------------------------- 1 | #' @name Boin-class 2 | #' @title The BOIN design as a Cumulative-Cohort Design (CCD) subclass 3 | #' 4 | #' @details 5 | #' TODO: Provide references, and note clearly the choice of defaults. 6 | #' Also provide citations to BOIN paper(s). 7 | #' @importFrom R6 R6Class 8 | #' @importFrom BOIN get.boundary select.mtd 9 | #' @export 10 | Boin <- R6Class("Boin", 11 | inherit = Ccd, 12 | public = list( 13 | #' @details 14 | #' Create a new `Boin` object. 15 | #' 16 | #' @param target Target toxicity rate 17 | #' @param cohort_max Upper bound on dose-wise enrollment 18 | #' @param enroll_max Upper bound on total enrollment 19 | #' @return A Boin object. 20 | #' 21 | #' @examples 22 | #' # TODO 23 | initialize = function(target, cohort_max, enroll_max) { 24 | private$target <- target 25 | bdy <- get.boundary(target = target 26 | ,ncohort = enroll_max 27 | ,cohortsize = 1 # TODO: Allow larger cohorts? 28 | ,n.earlystop = cohort_max 29 | ,extrasafe = FALSE 30 | ,offset = 0.05 31 | )$boundary_tab 32 | super$initialize(escalate = bdy[2,] 33 | ,deescalate = bdy[3,] 34 | ,eliminate = bdy[4,] 35 | ,cohort_max = cohort_max 36 | ,enroll_max = enroll_max 37 | ) 38 | } # 39 | ## TODO: Obtain the *final* BOIN dose recommendations 40 | ## via BOIN:select.mtd(). Note that this seems to 41 | ## require a general design making a distinction 42 | ## between dose-escalation decisions OT1H, and 43 | ## FINAL dose recommendations OTOH. 44 | ), # 45 | private = list( 46 | target = NA 47 | ) 48 | ) 49 | -------------------------------------------------------------------------------- /R/ccd.R: -------------------------------------------------------------------------------- 1 | #' @name Ccd-class 2 | #' @title An R6 class encapsulating Cumulative-Cohort Designs 3 | #' 4 | #' @details 5 | #' TODO: Explain the hierarchy of model classes, including connections 6 | #' with the executable specifications set forth in `exec/prolog/ccd.pl`. 7 | #' @references 8 | #' 1. Ivanova A, Flournoy N, Chung Y. Cumulative cohort design for dose-finding. 9 | #' Journal of Statistical Planning and Inference. 2007;137(7):2316-2327. 10 | #' \doi{10.1016/j.jspi.2006.07.009} 11 | #' 2. Liu S, Yuan Y. Bayesian optimal interval designs for phase I clinical trials. 12 | #' J R Stat Soc C. 2015;64(3):507-523. \doi{10.1111/rssc.12089} 13 | #' @importFrom R6 R6Class 14 | #' @export 15 | Ccd <- R6Class("Ccd", 16 | inherit = Cpe, 17 | public = list( 18 | #' @details 19 | #' Create a new `Ccd` object. 20 | #' 21 | #' @param escalate Escalation boundary 22 | #' @param deescalate Deescalation boundary 23 | #' @param eliminate Elimination boundary 24 | #' @param cohort_max Upper bound on dose-wise enrollment 25 | #' @param enroll_max Upper bound on total enrollment 26 | #' @return A `Ccd` object. 27 | #' 28 | #' @examples 29 | #' # TODO 30 | initialize = function(escalate, deescalate, eliminate, cohort_max, enroll_max) { 31 | private$escalate <- escalate 32 | private$deescalate <- deescalate 33 | ## The 'severe' action of dose elimination may not apply until some 34 | ## minimum cohort enrollment (e.g., 3), in which case \CRANpkg{BOIN} 35 | ## denotes inapplicable entries by `NA`. But converting these to `Inf` 36 | ## renders the 'lifting' of the constraint more elegantly: 37 | private$eliminate <- { eliminate[is.na(eliminate)] <- Inf; eliminate } 38 | private$cohort_max <- cohort_max 39 | private$enroll_max <- enroll_max 40 | }, 41 | #' @details 42 | #' Return dose recommendation for given tox/no-tox tallies. 43 | #' 44 | #' @param x A dose-wise vector of toxicity counts 45 | #' @param o A dose-wise vector of non-toxicity counts 46 | #' @param last_dose The most recently given dose, as required to implement 47 | #' cumulative-cohort-based escalation decisions. 48 | #' @param max_dose An upper limit on future dose levels 49 | #' @param ... Unused by `Ccd`; included for superclass method compatibility 50 | #' @return An object with components: 51 | #' * `$stop` - logical value indicating whether stop is indicated 52 | #' * `$mtd` - integer value, the recommended dose 53 | #' * `$max_dose` - integer value, a dose not to be exceeded henceforth. 54 | applied = function(x, o, last_dose, max_dose, ...){ 55 | tox <- x[last_dose] 56 | n <- tox + o[last_dose] 57 | rec <- if (tox >= private$eliminate[n]) 58 | max_dose <- last_dose-1 59 | else if (tox >= private$deescalate[n]) 60 | last_dose-1 61 | else if (tox <= private$escalate[n]) 62 | min(last_dose+1, max_dose) 63 | else 64 | last_dose 65 | 66 | stop <- ( rec == 0 || 67 | (x+o)[rec] >= private$cohort_max || 68 | sum(x+o) >= private$enroll_max ) 69 | 70 | return(list(mtd = rec, 71 | stop = stop, 72 | max_dose = max_dose)) 73 | } # 74 | ), # 75 | private = list( 76 | escalate = NA 77 | , deescalate = NA 78 | , eliminate = NA 79 | , cohort_max = NA 80 | , enroll_max = NA 81 | ) 82 | ) 83 | -------------------------------------------------------------------------------- /R/data.R: -------------------------------------------------------------------------------- 1 | #' Complete dose transition pathways (DTP) table for the VIOLA trial. 2 | #' 3 | #' This data set caches a long computation (17 minutes on a 2.6GHz i7) 4 | #' needed to build one package vignette. 5 | #' 6 | #' @format A data frame with 4^7 = 16384 rows and 15 columns, each row 7 | #' representing one possible path the trial could take: 8 | #' \describe{ 9 | #' \item{D0}{Initial dose level} 10 | #' \item{T1}{Number of toxicities observed in first cohort} 11 | #' \item{D1}{Dose recommendation after the first cohort} 12 | #' \item{T2}{Number of toxicities observed in second cohort} 13 | #' \item{D2}{Dose recommendation after the second cohort} 14 | #' \item{T3}{Number of toxicities observed in third cohort} 15 | #' \item{D3}{Dose recommendation after the third cohort} 16 | #' \item{T4}{Number of toxicities observed in fourth cohort} 17 | #' \item{D4}{Dose recommendation after the fourth cohort} 18 | #' \item{T5}{Number of toxicities observed in fifth cohort} 19 | #' \item{D5}{Dose recommendation after the fifth cohort} 20 | #' \item{T6}{Number of toxicities observed in sixth cohort} 21 | #' \item{D6}{Dose recommendation after the sixth cohort} 22 | #' \item{T7}{Number of toxicities observed in seventh cohort} 23 | #' \item{D7}{Dose recommendation after the seventh cohort} 24 | #' } 25 | #' 26 | #' @seealso 27 | #' Documentation of the \code{\link[dtpcrm]{calculate_dtps}} function. 28 | #' 29 | "viola_dtp" 30 | -------------------------------------------------------------------------------- /R/dtp.R: -------------------------------------------------------------------------------- 1 | #' A supremely faster version of a function from `dtpcrm` v0.1.1 2 | #' 3 | #' Originally, the sampling in `stats::rnorm()` (see inline comments in code) 4 | #' consumed 53% of run-time in a 6-cohort VIOLA DTP. After this change, it 5 | #' doesn't even show up! More importantly, the consumption is now dominated 6 | #' by (at 75%) by the objective function 'f' in integrate(). 7 | #' @param x A object of class `mtd` 8 | #' @param tox_lim Scalar upper threshold on estimated toxicity rate 9 | #' @param prob_cert Confidence level for threshold exceedance 10 | #' @param dose Integer scalar, the dose being considered 11 | #' @param suppress_dose Logical; if TRUE the MTD is set to `NA` when 12 | #' trial stop is recommended. 13 | #' @return 14 | #' The `mtd` object x, with stop decision annotated 15 | #' @author Adapted by David C. Norris from original `dtpcrm::stop_for_excess_toxicity_empiric` 16 | #' @importFrom stats pnorm 17 | #' @export 18 | stop_for_excess_toxicity_empiric <- function (x, tox_lim, prob_cert, dose = 1, 19 | suppress_dose = TRUE) { 20 | post_beta_mean = x$estimate 21 | post_beta_var = x$post.var 22 | ## The following was massively wasteful, with the stats::rnorm() 23 | ## sampling itself consuming 53% of time in dtp(6)! 24 | ## > post_beta_samp = stats::rnorm(n = nsamps, mean = post_beta_mean, 25 | ## > sd = sqrt(post_beta_var)) 26 | ## > post_prob_tox_samp = x$prior[dose]^exp(post_beta_samp) 27 | ## > prob_too_toxic = mean(post_prob_tox_samp > tox_lim) 28 | ## Yet a bit of math suffices to compute this with ZERO MCSE, via pnorm(): 29 | prob_too_toxic <- pnorm(log(log(tox_lim)/log(x$prior[dose])), 30 | mean = post_beta_mean, sd = sqrt(post_beta_var)) 31 | stop_decision = prob_too_toxic > prob_cert 32 | x$stop = stop_decision 33 | if (stop_decision) { 34 | x$stop_reason = paste0("Prob(Prob(Tox[", dose, "]) > ", 35 | tox_lim, ") = ", round(prob_too_toxic, 3), " > ", 36 | prob_cert) 37 | if (suppress_dose) 38 | x$mtd = NA 39 | } 40 | return(x) 41 | } 42 | -------------------------------------------------------------------------------- /R/dutycycle.R: -------------------------------------------------------------------------------- 1 | #' Plot duty cycle from performance report on a parallel computation 2 | #' 3 | #' This is intended for application to the tables which get attached 4 | #' to `Cpe` instances after invocation of the `$trace_paths()` method. 5 | #' But any table with columns named `pid`, `t1` and `t2` suffices. 6 | #' @param perftab A performance table with columns: 7 | #' * `pid` An integer, character or factor with process ids 8 | #' * `t1`, `t2` Task start and end times, in milliseconds 9 | #' @param ... Optional parameters passed along to `lattice::xyplot` 10 | #' @param FUN A function for summarizing all workers' duty cycles 11 | #' @param layout Trellis layout, passed to `xyplot` 12 | #' @return An `xyplot` with a duty-cycle panel for each worker, 13 | #' plus an overall average 14 | #' @examples 15 | #' if (interactive()) { 16 | #' ## Example from Braun2020 17 | #' d1_maxn <- 5 18 | #' cum_maxn <- 10 19 | #' mod <- Crm$new(skeleton = c(0.03, 0.11, 0.25, 0.42, 0.58, 0.71), 20 | #' scale = 0.85, # aka 'sigma' 21 | #' target = 0.25)$ 22 | #' no_skip_esc(TRUE)$ # compare Braun's 'restrict = T' 23 | #' no_skip_deesc(FALSE)$ 24 | #' stop_func(function(x) { 25 | #' enrolled <- tabulate(x$level, nbins = length(x$prior)) 26 | #' x$stop <- enrolled[1] >= d1_maxn || max(enrolled) >= cum_maxn 27 | #' x 28 | #' }) 29 | #' mod$trace_paths(1, rep(2, 13), unroll = 4 30 | #' , mc.cores = parallelly::availableCores(omit=2)) 31 | #' print(mod$performance) 32 | #' plot_dutycycle(mod$performance) 33 | #' } 34 | #' @export 35 | plot_dutycycle <- function(perftab, ..., FUN = c(workers = sum), layout = c(1, NA)) { 36 | jpt <- perftab 37 | jpt$job <- seq(nrow(jpt)) # TODO: Better if perftab supplies names 38 | 39 | jpt$pid <- as.factor(jpt$pid) # TODO: Get 'pid' colname from a formula 40 | 41 | T <- 0:ceiling(max(jpt$t2)) 42 | m <- matrix(FALSE, nrow=length(T), ncol=nlevels(jpt$pid)) 43 | dimnames(m) <- list(t = T, pid = levels(jpt$pid)) 44 | 45 | for (j in 1:nrow(jpt)) { 46 | pid <- jpt$pid[j] 47 | m[,pid] <- m[,pid] | (jpt$t1[j] < T & T < jpt$t2[j]) 48 | } 49 | 50 | ## Add a summary column 51 | m <- addmargins(m, margin = 2, FUN = FUN) 52 | 53 | ## Reshape this matrix to 'tall' form yielding series to plot 54 | dt <- data.table(t = T 55 | , active = 1.0 * as.vector(m) 56 | , pid = factor(rep(colnames(m), each=nrow(m))) 57 | ) 58 | 59 | lattice::xyplot(active ~ t | pid, data = dt, type='l' 60 | , layout=layout, as.table=TRUE 61 | , ylab = "" 62 | , xlab = "Sys.time() since parallelization [ms]" 63 | , scales = list(y = list(at = NULL)) 64 | , par.strip.text = list(cex = 0.6) 65 | , ... 66 | ) 67 | } 68 | -------------------------------------------------------------------------------- /R/extendr-wrappers.R: -------------------------------------------------------------------------------- 1 | # Generated by extendr: Do not edit by hand 2 | # 3 | # This file was created with the following call: 4 | # .Call("wrap__make_precautionary_wrappers", use_symbols = TRUE, package_name = "precautionary") 5 | 6 | #' @docType package 7 | #' @usage NULL 8 | #' @useDynLib precautionary, .registration = TRUE 9 | NULL 10 | 11 | #' Rust implementation of `dfcrm::crmh*` integrands for w==1 case 12 | #' 13 | #' @param a Numeric vector of evaluation points 14 | #' @param ln_x A numeric vector of dose-wise prior log-probabilities of toxicity 15 | #' @param tox A numeric vector; a dose-wise tally of toxicities 16 | #' @param nos A numeric vector; a dose-wise tally of non-toxicities 17 | #' @param s Scalar scale factor 18 | #' @param b Order of moment to calculate (0, 1 or 2) 19 | #' @export 20 | crmh_xo <- function(a, ln_x, tox, nos, s, b) .Call(wrap__crmh_xo, a, ln_x, tox, nos, s, b) 21 | 22 | #' Rust implementation of `dfcrm::crmh*` integrands 23 | #' 24 | #' @param a Numeric vector of evaluation points 25 | #' @param ln_x A numeric vector of dose-wise prior log-probabilities of toxicity 26 | #' @param w Patient-wise weights (used for TITE CRM), also encoding toxicity 27 | #' by `w[i] == 0.0`. 28 | #' @param s Scalar scale factor 29 | #' @describeIn crmh Posterior for 1-parameter empiric (aka 'power') model 30 | #' @export 31 | crmh <- function(a, ln_x, w, s) .Call(wrap__crmh, a, ln_x, w, s) 32 | 33 | #' @describeIn crmh Integrand for 1st moment of empiric posterior 34 | #' @export 35 | crmht <- function(a, ln_x, w, s) .Call(wrap__crmht, a, ln_x, w, s) 36 | 37 | #' @describeIn crmh Integrand for 2nd moment of empiric posterior 38 | #' @export 39 | crmht2 <- function(a, ln_x, w, s) .Call(wrap__crmht2, a, ln_x, w, s) 40 | 41 | -------------------------------------------------------------------------------- /R/sysdata.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcnorris/precautionary/a0019fc6baaa0a01ce1cef1b75982fdd7ae52d80/R/sysdata.rda -------------------------------------------------------------------------------- /R/three3.R: -------------------------------------------------------------------------------- 1 | #' @name Cpe3_3-class 2 | #' @title An R6 class encapsulating precalculated CPE for 3+3 design 3 | #' 4 | #' @details 5 | #' TODO: Explain the hierarchy of model classes, including connections 6 | #' with the executable specifications set forth in `exec/prolog/ccd.pl`. 7 | #' @references 8 | #' 1. Korn EL, Midthune D, Chen TT, Rubinstein LV, Christian MC, Simon RM. 9 | #' A comparison of two phase I trial designs. *Stat Med*. 1994;13(18):1799-1806. 10 | #' \doi{10.1002/sim.4780131802} 11 | #' @importFrom R6 R6Class 12 | #' @export 13 | Cpe3_3 <- R6Class("Cpe3_3", 14 | inherit = Cpe, 15 | public = list( 16 | #' @details 17 | #' Create a new `Cpe3_3` object. 18 | #' 19 | #' @param D number of prespecified doses 20 | #' @return A `Cpe3_3` object. 21 | #' 22 | #' @examples 23 | #' # TODO 24 | initialize = function(D) { 25 | stopifnot("3+3 designs precalculated only for 2--8 doses" = D %in% 2:8) 26 | private$.max_dose <- D 27 | private$T <- precautionary:::T[[D]] 28 | private$b <- precautionary:::b[[D]] 29 | private$U <- precautionary:::U[[D]] 30 | }, 31 | #' @details 32 | #' Query number of doses 33 | #' @note This specializes the generic method of `Cpe` superclass, 34 | #' removing the possibility of updating the state. 35 | #' 36 | #' @return Self (invisibly), unless `D` is missing, 37 | #' in which case the top dose, an integer, is returned. 38 | max_dose = function() { 39 | #if (missing(D)) 40 | return(private$.max_dose) 41 | #private$.max_dose <- D 42 | #invisible(self) 43 | }, 44 | #' @details 45 | #' Get the `b` vector and `U` matrix 46 | #' @return Named list with components `b` and `U` 47 | bU = function() { 48 | list(b = private$b, U = private$U) 49 | }, 50 | #' @details 51 | #' Get the number `J` of paths 52 | #' @return Integer number of paths 53 | J = function() { 54 | length(private$b) 55 | }, 56 | #' @details 57 | #' No-op specialization of superclass method 58 | #' 59 | #' Since `Cpe3_3` has cached paths precomputed by Prolog code, 60 | #' it does not need to support this method. 61 | #' 62 | #' @param ... Ignored 63 | #' @return Self, invisibly 64 | trace_paths = function(...){ 65 | message("No-op `Cpe3_3$trace_paths` invoked unnecessarily") 66 | invisible(self) 67 | }, 68 | #' @details 69 | #' Refuse superclass method 70 | #' 71 | #' @return An error 72 | path_matrix = function() { 73 | stop("`Cpe3_3$path_matrix()` unimplemented") 74 | }, 75 | #' @details 76 | #' Refuse superclass method 77 | #' 78 | #' @return An error 79 | path_rx = function() { 80 | stop("`Cpe3_3$path_rx()` unimplemented") 81 | } 82 | ) # 83 | ) 84 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | # NOTE: 2 | # Taken wholesale from https://github.com/yutannihilation/string2path/blob/main/configure, 3 | # which is based on configure script of package 'gifski' (https://github.com/r-rust/gifski/), 4 | # distributed under the MIT license, authored by Jeroen Ooms. 5 | 6 | # Even when `cargo` is on `PATH`, `rustc` might not (c.f. https://github.com/yutannihilation/string2path/issues/4). 7 | export PATH="$HOME/.cargo/bin:$PATH" 8 | 9 | # If cargo command already exists, do nothing. 10 | cargo --version 11 | if [ $? -eq 0 ]; then 12 | exit 0 13 | fi 14 | 15 | # If the OS is macOS, try installing cargo to a temporary dir on the fly. 16 | # I feel this is doing too much, but this is needed to let the CRAN build success, 17 | # (c.f. https://github.com/yutannihilation/string2path/issues/8), so I rely on 18 | # this for now. Eventually, I will provide staticlib for macOS, just like I do 19 | # for Windows. 20 | if [ "`uname`" = "Darwin" ]; then 21 | echo "Note: installing cargo to a temporary dir..." 22 | 23 | # autobrew is a "Fork of homebrew for building CRAN packages" (https://github.com/autobrew/) 24 | # This also tweaks src/Makevars to use TMPDIR instead of CARGO_HOME. 25 | curl "https://autobrew.github.io/scripts/rust" -sSf | sh 26 | 27 | # If the installation succeeds, exit here. 28 | if [ $? -eq 0 ]; then 29 | exit 0 30 | fi 31 | fi 32 | 33 | # If cargo is not found, display a friendly message and exit with error. 34 | 35 | echo "------------------ RUST COMPILER NOT FOUND --------------------" 36 | echo "" 37 | echo "Please refer to " 38 | echo "" 39 | echo "---------------------------------------------------------------" 40 | echo "" 41 | 42 | exit 1 43 | -------------------------------------------------------------------------------- /data/viola_dtp.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcnorris/precautionary/a0019fc6baaa0a01ce1cef1b75982fdd7ae52d80/data/viola_dtp.rda -------------------------------------------------------------------------------- /demo/00Index: -------------------------------------------------------------------------------- 1 | EscRisk Run Shiny app 'EscRisk' (try its [Tutorial] button!) 2 | -------------------------------------------------------------------------------- /demo/EscRisk.R: -------------------------------------------------------------------------------- 1 | # Running Shiny app 'EscRisk' ... 2 | old <- options(device.ask.default = FALSE) 3 | appDir <- system.file("shiny-apps", "EscRisk", package = "precautionary") 4 | shiny::runApp(appDir, display.mode = "normal") 5 | options(old) 6 | -------------------------------------------------------------------------------- /docs/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcnorris/precautionary/a0019fc6baaa0a01ce1cef1b75982fdd7ae52d80/docs/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /docs/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcnorris/precautionary/a0019fc6baaa0a01ce1cef1b75982fdd7ae52d80/docs/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /docs/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcnorris/precautionary/a0019fc6baaa0a01ce1cef1b75982fdd7ae52d80/docs/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /docs/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcnorris/precautionary/a0019fc6baaa0a01ce1cef1b75982fdd7ae52d80/docs/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /docs/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcnorris/precautionary/a0019fc6baaa0a01ce1cef1b75982fdd7ae52d80/docs/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /docs/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcnorris/precautionary/a0019fc6baaa0a01ce1cef1b75982fdd7ae52d80/docs/apple-touch-icon.png -------------------------------------------------------------------------------- /docs/articles/DTP-vs-Korn94_files/DiagrammeR-styles-0.2/styles.css: -------------------------------------------------------------------------------- 1 | .DiagrammeR,.grViz pre { 2 | white-space: pre-wrap; /* CSS 3 */ 3 | white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ 4 | white-space: -pre-wrap; /* Opera 4-6 */ 5 | white-space: -o-pre-wrap; /* Opera 7 */ 6 | word-wrap: break-word; /* Internet Explorer 5.5+ */ 7 | } 8 | 9 | .DiagrammeR g .label { 10 | font-family: Helvetica; 11 | font-size: 14px; 12 | color: #333333; 13 | } 14 | 15 | -------------------------------------------------------------------------------- /docs/articles/DTP-vs-Korn94_files/accessible-code-block-0.0.1/empty-anchor.js: -------------------------------------------------------------------------------- 1 | // Hide empty tag within highlighted CodeBlock for screen reader accessibility (see https://github.com/jgm/pandoc/issues/6352#issuecomment-626106786) --> 2 | // v0.0.1 3 | // Written by JooYoung Seo (jooyoung@psu.edu) and Atsushi Yasumoto on June 1st, 2020. 4 | 5 | document.addEventListener('DOMContentLoaded', function() { 6 | const codeList = document.getElementsByClassName("sourceCode"); 7 | for (var i = 0; i < codeList.length; i++) { 8 | var linkList = codeList[i].getElementsByTagName('a'); 9 | for (var j = 0; j < linkList.length; j++) { 10 | if (linkList[j].innerHTML === "") { 11 | linkList[j].setAttribute('aria-hidden', 'true'); 12 | } 13 | } 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /docs/articles/DTP-vs-Korn94_files/grViz-binding-1.0.6.1/grViz.js: -------------------------------------------------------------------------------- 1 | HTMLWidgets.widget({ 2 | 3 | name: 'grViz', 4 | 5 | type: 'output', 6 | 7 | initialize: function(el, width, height) { 8 | 9 | return { 10 | // TODO: add instance fields as required 11 | }; 12 | }, 13 | 14 | renderValue: function(el, x, instance) { 15 | // Use this to sort of make our diagram responsive 16 | // or at a minimum fit within the bounds set by htmlwidgets 17 | // for the parent container 18 | function makeResponsive(el){ 19 | var svg = el.getElementsByTagName("svg")[0]; 20 | if (svg) { 21 | if (svg.width) {svg.removeAttribute("width")} 22 | if (svg.height) {svg.removeAttribute("height")} 23 | svg.style.width = "100%"; 24 | svg.style.height = "100%"; 25 | } 26 | } 27 | 28 | if (x.diagram !== "") { 29 | 30 | if (typeof x.config === "undefined"){ 31 | x.config = {}; 32 | x.config.engine = "dot"; 33 | x.config.options = {}; 34 | } 35 | 36 | try { 37 | 38 | el.innerHTML = Viz(x.diagram, format="svg", engine=x.config.engine, options=x.config.options); 39 | 40 | makeResponsive(el); 41 | 42 | if (HTMLWidgets.shinyMode) { 43 | // Get widget id 44 | var id = el.id; 45 | 46 | $("#" + id + " .node").click(function(e) { 47 | // Get node id 48 | var nodeid = e.currentTarget.id; 49 | // Get node text object and make an array 50 | var node_texts = $("#" + nodeid + " text"); 51 | //var node_path = $("#" + nodeid + " path")[0]; 52 | var text_array = node_texts.map(function() {return $(this).text(); }).toArray(); 53 | // Build return object *obj* with node-id, node text values and node fill 54 | var obj = { 55 | id: nodeid, 56 | //fill: node_path.attributes.fill.nodeValue, 57 | //outerHMTL: node_path.outerHTML, 58 | nodeValues: text_array 59 | }; 60 | // Send *obj* to Shiny's inputs (input$[id]+_click e.g.: input$vtree_click)) 61 | Shiny.setInputValue(id + "_click", obj, {priority: "event"}); 62 | }); 63 | } 64 | 65 | // set up a container for tasks to perform after completion 66 | // one example would be add callbacks for event handling 67 | // styling 68 | if (typeof x.tasks !== "undefined") { 69 | if ((typeof x.tasks.length === "undefined") || 70 | (typeof x.tasks === "function")) { 71 | // handle a function not enclosed in array 72 | // should be able to remove once using jsonlite 73 | x.tasks = [x.tasks]; 74 | } 75 | x.tasks.map(function(t){ 76 | // for each tasks add it to the mermaid.tasks with el 77 | t.call(el); 78 | }); 79 | } 80 | } catch(e){ 81 | var p = document.createElement("pre"); 82 | p.innerText = e; 83 | el.appendChild(p); 84 | } 85 | } 86 | 87 | }, 88 | 89 | resize: function(el, width, height, instance) { 90 | } 91 | }); 92 | -------------------------------------------------------------------------------- /docs/articles/DTP-vs-Korn94_files/header-attrs-2.7/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/DTP-vs-Korn94_files/header-attrs-2.8/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/DTP-vs-Korn94_files/header-attrs-2.9/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/FDA-proactive_files/accessible-code-block-0.0.1/empty-anchor.js: -------------------------------------------------------------------------------- 1 | // Hide empty tag within highlighted CodeBlock for screen reader accessibility (see https://github.com/jgm/pandoc/issues/6352#issuecomment-626106786) --> 2 | // v0.0.1 3 | // Written by JooYoung Seo (jooyoung@psu.edu) and Atsushi Yasumoto on June 1st, 2020. 4 | 5 | document.addEventListener('DOMContentLoaded', function() { 6 | const codeList = document.getElementsByClassName("sourceCode"); 7 | for (var i = 0; i < codeList.length; i++) { 8 | var linkList = codeList[i].getElementsByTagName('a'); 9 | for (var j = 0; j < linkList.length; j++) { 10 | if (linkList[j].innerHTML === "") { 11 | linkList[j].setAttribute('aria-hidden', 'true'); 12 | } 13 | } 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /docs/articles/FDA-proactive_files/figure-html/hyperprior-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcnorris/precautionary/a0019fc6baaa0a01ce1cef1b75982fdd7ae52d80/docs/articles/FDA-proactive_files/figure-html/hyperprior-1.png -------------------------------------------------------------------------------- /docs/articles/FDA-proactive_files/header-attrs-2.7/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/FDA-proactive_files/header-attrs-2.8/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/FDA-proactive_files/header-attrs-2.9/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/FDA-proactive_files/kePrint-0.0.1/kePrint.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(){ 2 | if (typeof $('[data-toggle="tooltip"]').tooltip === 'function') { 3 | $('[data-toggle="tooltip"]').tooltip(); 4 | } 5 | if ($('[data-toggle="popover"]').popover === 'function') { 6 | $('[data-toggle="popover"]').popover(); 7 | } 8 | }); 9 | -------------------------------------------------------------------------------- /docs/articles/Intro_files/accessible-code-block-0.0.1/empty-anchor.js: -------------------------------------------------------------------------------- 1 | // Hide empty tag within highlighted CodeBlock for screen reader accessibility (see https://github.com/jgm/pandoc/issues/6352#issuecomment-626106786) --> 2 | // v0.0.1 3 | // Written by JooYoung Seo (jooyoung@psu.edu) and Atsushi Yasumoto on June 1st, 2020. 4 | 5 | document.addEventListener('DOMContentLoaded', function() { 6 | const codeList = document.getElementsByClassName("sourceCode"); 7 | for (var i = 0; i < codeList.length; i++) { 8 | var linkList = codeList[i].getElementsByTagName('a'); 9 | for (var j = 0; j < linkList.length; j++) { 10 | if (linkList[j].innerHTML === "") { 11 | linkList[j].setAttribute('aria-hidden', 'true'); 12 | } 13 | } 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /docs/articles/Intro_files/figure-html/Raleigh-distribution-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcnorris/precautionary/a0019fc6baaa0a01ce1cef1b75982fdd7ae52d80/docs/articles/Intro_files/figure-html/Raleigh-distribution-1.png -------------------------------------------------------------------------------- /docs/articles/Intro_files/figure-html/hyperprior-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcnorris/precautionary/a0019fc6baaa0a01ce1cef1b75982fdd7ae52d80/docs/articles/Intro_files/figure-html/hyperprior-1.png -------------------------------------------------------------------------------- /docs/articles/Intro_files/figure-html/unnamed-chunk-3-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcnorris/precautionary/a0019fc6baaa0a01ce1cef1b75982fdd7ae52d80/docs/articles/Intro_files/figure-html/unnamed-chunk-3-1.png -------------------------------------------------------------------------------- /docs/articles/Intro_files/header-attrs-2.7/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/Intro_files/header-attrs-2.8/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/Intro_files/header-attrs-2.9/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/Intro_files/kePrint-0.0.1/kePrint.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(){ 2 | if (typeof $('[data-toggle="tooltip"]').tooltip === 'function') { 3 | $('[data-toggle="tooltip"]').tooltip(); 4 | } 5 | if ($('[data-toggle="popover"]').popover === 'function') { 6 | $('[data-toggle="popover"]').popover(); 7 | } 8 | }); 9 | -------------------------------------------------------------------------------- /docs/articles/Intro_files/lightable-0.0.1/lightable.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * lightable v0.0.1 3 | * Copyright 2020 Hao Zhu 4 | * Licensed under MIT (https://github.com/haozhu233/kableExtra/blob/master/LICENSE) 5 | */ 6 | 7 | .lightable-minimal { 8 | border-collapse: separate; 9 | border-spacing: 16px 1px; 10 | width: 100%; 11 | margin-bottom: 10px; 12 | } 13 | 14 | .lightable-minimal td { 15 | margin-left: 5px; 16 | margin-right: 5px; 17 | } 18 | 19 | .lightable-minimal th { 20 | margin-left: 5px; 21 | margin-right: 5px; 22 | } 23 | 24 | .lightable-minimal thead tr:last-child th { 25 | border-bottom: 2px solid #00000050; 26 | empty-cells: hide; 27 | 28 | } 29 | 30 | .lightable-minimal tbody tr:first-child td { 31 | padding-top: 0.5em; 32 | } 33 | 34 | .lightable-minimal.lightable-hover tbody tr:hover { 35 | background-color: #f5f5f5; 36 | } 37 | 38 | .lightable-minimal.lightable-striped tbody tr:nth-child(even) { 39 | background-color: #f5f5f5; 40 | } 41 | 42 | .lightable-classic { 43 | border-top: 0.16em solid #111111; 44 | border-bottom: 0.16em solid #111111; 45 | width: 100%; 46 | margin-bottom: 10px; 47 | margin: 10px 5px; 48 | } 49 | 50 | .lightable-classic tfoot tr td { 51 | border: 0; 52 | } 53 | 54 | .lightable-classic tfoot tr:first-child td { 55 | border-top: 0.14em solid #111111; 56 | } 57 | 58 | .lightable-classic caption { 59 | color: #222222; 60 | } 61 | 62 | .lightable-classic td { 63 | padding-left: 5px; 64 | padding-right: 5px; 65 | color: #222222; 66 | } 67 | 68 | .lightable-classic th { 69 | padding-left: 5px; 70 | padding-right: 5px; 71 | font-weight: normal; 72 | color: #222222; 73 | } 74 | 75 | .lightable-classic thead tr:last-child th { 76 | border-bottom: 0.10em solid #111111; 77 | } 78 | 79 | .lightable-classic.lightable-hover tbody tr:hover { 80 | background-color: #F9EEC1; 81 | } 82 | 83 | .lightable-classic.lightable-striped tbody tr:nth-child(even) { 84 | background-color: #f5f5f5; 85 | } 86 | 87 | .lightable-classic-2 { 88 | border-top: 3px double #111111; 89 | border-bottom: 3px double #111111; 90 | width: 100%; 91 | margin-bottom: 10px; 92 | } 93 | 94 | .lightable-classic-2 tfoot tr td { 95 | border: 0; 96 | } 97 | 98 | .lightable-classic-2 tfoot tr:first-child td { 99 | border-top: 3px double #111111; 100 | } 101 | 102 | .lightable-classic-2 caption { 103 | color: #222222; 104 | } 105 | 106 | .lightable-classic-2 td { 107 | padding-left: 5px; 108 | padding-right: 5px; 109 | color: #222222; 110 | } 111 | 112 | .lightable-classic-2 th { 113 | padding-left: 5px; 114 | padding-right: 5px; 115 | font-weight: normal; 116 | color: #222222; 117 | } 118 | 119 | .lightable-classic-2 tbody tr:last-child td { 120 | border-bottom: 3px double #111111; 121 | } 122 | 123 | .lightable-classic-2 thead tr:last-child th { 124 | border-bottom: 1px solid #111111; 125 | } 126 | 127 | .lightable-classic-2.lightable-hover tbody tr:hover { 128 | background-color: #F9EEC1; 129 | } 130 | 131 | .lightable-classic-2.lightable-striped tbody tr:nth-child(even) { 132 | background-color: #f5f5f5; 133 | } 134 | 135 | .lightable-material { 136 | min-width: 100%; 137 | white-space: nowrap; 138 | table-layout: fixed; 139 | font-family: Roboto, sans-serif; 140 | border: 1px solid #EEE; 141 | border-collapse: collapse; 142 | margin-bottom: 10px; 143 | } 144 | 145 | .lightable-material tfoot tr td { 146 | border: 0; 147 | } 148 | 149 | .lightable-material tfoot tr:first-child td { 150 | border-top: 1px solid #EEE; 151 | } 152 | 153 | .lightable-material th { 154 | height: 56px; 155 | padding-left: 16px; 156 | padding-right: 16px; 157 | } 158 | 159 | .lightable-material td { 160 | height: 52px; 161 | padding-left: 16px; 162 | padding-right: 16px; 163 | border-top: 1px solid #eeeeee; 164 | } 165 | 166 | .lightable-material.lightable-hover tbody tr:hover { 167 | background-color: #f5f5f5; 168 | } 169 | 170 | .lightable-material.lightable-striped tbody tr:nth-child(even) { 171 | background-color: #f5f5f5; 172 | } 173 | 174 | .lightable-material.lightable-striped tbody td { 175 | border: 0; 176 | } 177 | 178 | .lightable-material.lightable-striped thead tr:last-child th { 179 | border-bottom: 1px solid #ddd; 180 | } 181 | 182 | .lightable-material-dark { 183 | min-width: 100%; 184 | white-space: nowrap; 185 | table-layout: fixed; 186 | font-family: Roboto, sans-serif; 187 | border: 1px solid #FFFFFF12; 188 | border-collapse: collapse; 189 | margin-bottom: 10px; 190 | background-color: #363640; 191 | } 192 | 193 | .lightable-material-dark tfoot tr td { 194 | border: 0; 195 | } 196 | 197 | .lightable-material-dark tfoot tr:first-child td { 198 | border-top: 1px solid #FFFFFF12; 199 | } 200 | 201 | .lightable-material-dark th { 202 | height: 56px; 203 | padding-left: 16px; 204 | padding-right: 16px; 205 | color: #FFFFFF60; 206 | } 207 | 208 | .lightable-material-dark td { 209 | height: 52px; 210 | padding-left: 16px; 211 | padding-right: 16px; 212 | color: #FFFFFF; 213 | border-top: 1px solid #FFFFFF12; 214 | } 215 | 216 | .lightable-material-dark.lightable-hover tbody tr:hover { 217 | background-color: #FFFFFF12; 218 | } 219 | 220 | .lightable-material-dark.lightable-striped tbody tr:nth-child(even) { 221 | background-color: #FFFFFF12; 222 | } 223 | 224 | .lightable-material-dark.lightable-striped tbody td { 225 | border: 0; 226 | } 227 | 228 | .lightable-material-dark.lightable-striped thead tr:last-child th { 229 | border-bottom: 1px solid #FFFFFF12; 230 | } 231 | 232 | .lightable-paper { 233 | width: 100%; 234 | margin-bottom: 10px; 235 | color: #444; 236 | } 237 | 238 | .lightable-paper tfoot tr td { 239 | border: 0; 240 | } 241 | 242 | .lightable-paper tfoot tr:first-child td { 243 | border-top: 1px solid #00000020; 244 | } 245 | 246 | .lightable-paper thead tr:last-child th { 247 | color: #666; 248 | vertical-align: bottom; 249 | border-bottom: 1px solid #00000020; 250 | line-height: 1.15em; 251 | padding: 10px 5px; 252 | } 253 | 254 | .lightable-paper td { 255 | vertical-align: middle; 256 | border-bottom: 1px solid #00000010; 257 | line-height: 1.15em; 258 | padding: 7px 5px; 259 | } 260 | 261 | .lightable-paper.lightable-hover tbody tr:hover { 262 | background-color: #F9EEC1; 263 | } 264 | 265 | .lightable-paper.lightable-striped tbody tr:nth-child(even) { 266 | background-color: #00000008; 267 | } 268 | 269 | .lightable-paper.lightable-striped tbody td { 270 | border: 0; 271 | } 272 | 273 | -------------------------------------------------------------------------------- /docs/articles/MCSE-Free_files/accessible-code-block-0.0.1/empty-anchor.js: -------------------------------------------------------------------------------- 1 | // Hide empty tag within highlighted CodeBlock for screen reader accessibility (see https://github.com/jgm/pandoc/issues/6352#issuecomment-626106786) --> 2 | // v0.0.1 3 | // Written by JooYoung Seo (jooyoung@psu.edu) and Atsushi Yasumoto on June 1st, 2020. 4 | 5 | document.addEventListener('DOMContentLoaded', function() { 6 | const codeList = document.getElementsByClassName("sourceCode"); 7 | for (var i = 0; i < codeList.length; i++) { 8 | var linkList = codeList[i].getElementsByTagName('a'); 9 | for (var j = 0; j < linkList.length; j++) { 10 | if (linkList[j].innerHTML === "") { 11 | linkList[j].setAttribute('aria-hidden', 'true'); 12 | } 13 | } 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /docs/articles/MCSE-Free_files/figure-html/kraken-plot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcnorris/precautionary/a0019fc6baaa0a01ce1cef1b75982fdd7ae52d80/docs/articles/MCSE-Free_files/figure-html/kraken-plot-1.png -------------------------------------------------------------------------------- /docs/articles/MCSE-Free_files/header-attrs-2.7/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/MCSE-Free_files/header-attrs-2.8/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/MCSE-Free_files/header-attrs-2.9/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/articles/MCSE-Free_files/kePrint-0.0.1/kePrint.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(){ 2 | if (typeof $('[data-toggle="tooltip"]').tooltip === 'function') { 3 | $('[data-toggle="tooltip"]').tooltip(); 4 | } 5 | if ($('[data-toggle="popover"]').popover === 'function') { 6 | $('[data-toggle="popover"]').popover(); 7 | } 8 | }); 9 | -------------------------------------------------------------------------------- /docs/articles/Safety-Schematic-via-CPE_files/accessible-code-block-0.0.1/empty-anchor.js: -------------------------------------------------------------------------------- 1 | // Hide empty tag within highlighted CodeBlock for screen reader accessibility (see https://github.com/jgm/pandoc/issues/6352#issuecomment-626106786) --> 2 | // v0.0.1 3 | // Written by JooYoung Seo (jooyoung@psu.edu) and Atsushi Yasumoto on June 1st, 2020. 4 | 5 | document.addEventListener('DOMContentLoaded', function() { 6 | const codeList = document.getElementsByClassName("sourceCode"); 7 | for (var i = 0; i < codeList.length; i++) { 8 | var linkList = codeList[i].getElementsByTagName('a'); 9 | for (var j = 0; j < linkList.length; j++) { 10 | if (linkList[j].innerHTML === "") { 11 | linkList[j].setAttribute('aria-hidden', 'true'); 12 | } 13 | } 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /docs/articles/Safety-Schematic-via-CPE_files/figure-html/VIOLA-dose-scaling-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcnorris/precautionary/a0019fc6baaa0a01ce1cef1b75982fdd7ae52d80/docs/articles/Safety-Schematic-via-CPE_files/figure-html/VIOLA-dose-scaling-1.png -------------------------------------------------------------------------------- /docs/articles/Safety-Schematic-via-CPE_files/figure-html/contourplot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcnorris/precautionary/a0019fc6baaa0a01ce1cef1b75982fdd7ae52d80/docs/articles/Safety-Schematic-via-CPE_files/figure-html/contourplot-1.png -------------------------------------------------------------------------------- /docs/articles/Safety-Schematic-via-CPE_files/figure-html/fatalities-vs-kappa-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcnorris/precautionary/a0019fc6baaa0a01ce1cef1b75982fdd7ae52d80/docs/articles/Safety-Schematic-via-CPE_files/figure-html/fatalities-vs-kappa-1.png -------------------------------------------------------------------------------- /docs/articles/Safety-Schematic-via-CPE_files/figure-html/skeleton-as-expectation-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcnorris/precautionary/a0019fc6baaa0a01ce1cef1b75982fdd7ae52d80/docs/articles/Safety-Schematic-via-CPE_files/figure-html/skeleton-as-expectation-1.png -------------------------------------------------------------------------------- /docs/articles/Safety-Schematic-via-CPE_files/figure-html/skeleton-log-match-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcnorris/precautionary/a0019fc6baaa0a01ce1cef1b75982fdd7ae52d80/docs/articles/Safety-Schematic-via-CPE_files/figure-html/skeleton-log-match-1.png -------------------------------------------------------------------------------- /docs/articles/Safety-Schematic-via-CPE_files/header-attrs-2.9/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /docs/bootstrap-toc.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) 3 | * Copyright 2015 Aidan Feldman 4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ 5 | 6 | /* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */ 7 | 8 | /* All levels of nav */ 9 | nav[data-toggle='toc'] .nav > li > a { 10 | display: block; 11 | padding: 4px 20px; 12 | font-size: 13px; 13 | font-weight: 500; 14 | color: #767676; 15 | } 16 | nav[data-toggle='toc'] .nav > li > a:hover, 17 | nav[data-toggle='toc'] .nav > li > a:focus { 18 | padding-left: 19px; 19 | color: #563d7c; 20 | text-decoration: none; 21 | background-color: transparent; 22 | border-left: 1px solid #563d7c; 23 | } 24 | nav[data-toggle='toc'] .nav > .active > a, 25 | nav[data-toggle='toc'] .nav > .active:hover > a, 26 | nav[data-toggle='toc'] .nav > .active:focus > a { 27 | padding-left: 18px; 28 | font-weight: bold; 29 | color: #563d7c; 30 | background-color: transparent; 31 | border-left: 2px solid #563d7c; 32 | } 33 | 34 | /* Nav: second level (shown on .active) */ 35 | nav[data-toggle='toc'] .nav .nav { 36 | display: none; /* Hide by default, but at >768px, show it */ 37 | padding-bottom: 10px; 38 | } 39 | nav[data-toggle='toc'] .nav .nav > li > a { 40 | padding-top: 1px; 41 | padding-bottom: 1px; 42 | padding-left: 30px; 43 | font-size: 12px; 44 | font-weight: normal; 45 | } 46 | nav[data-toggle='toc'] .nav .nav > li > a:hover, 47 | nav[data-toggle='toc'] .nav .nav > li > a:focus { 48 | padding-left: 29px; 49 | } 50 | nav[data-toggle='toc'] .nav .nav > .active > a, 51 | nav[data-toggle='toc'] .nav .nav > .active:hover > a, 52 | nav[data-toggle='toc'] .nav .nav > .active:focus > a { 53 | padding-left: 28px; 54 | font-weight: 500; 55 | } 56 | 57 | /* from https://github.com/twbs/bootstrap/blob/e38f066d8c203c3e032da0ff23cd2d6098ee2dd6/docs/assets/css/src/docs.css#L631-L634 */ 58 | nav[data-toggle='toc'] .nav > .active > ul { 59 | display: block; 60 | } 61 | -------------------------------------------------------------------------------- /docs/bootstrap-toc.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) 3 | * Copyright 2015 Aidan Feldman 4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ 5 | (function() { 6 | 'use strict'; 7 | 8 | window.Toc = { 9 | helpers: { 10 | // return all matching elements in the set, or their descendants 11 | findOrFilter: function($el, selector) { 12 | // http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/ 13 | // http://stackoverflow.com/a/12731439/358804 14 | var $descendants = $el.find(selector); 15 | return $el.filter(selector).add($descendants).filter(':not([data-toc-skip])'); 16 | }, 17 | 18 | generateUniqueIdBase: function(el) { 19 | var text = $(el).text(); 20 | var anchor = text.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g, '-'); 21 | return anchor || el.tagName.toLowerCase(); 22 | }, 23 | 24 | generateUniqueId: function(el) { 25 | var anchorBase = this.generateUniqueIdBase(el); 26 | for (var i = 0; ; i++) { 27 | var anchor = anchorBase; 28 | if (i > 0) { 29 | // add suffix 30 | anchor += '-' + i; 31 | } 32 | // check if ID already exists 33 | if (!document.getElementById(anchor)) { 34 | return anchor; 35 | } 36 | } 37 | }, 38 | 39 | generateAnchor: function(el) { 40 | if (el.id) { 41 | return el.id; 42 | } else { 43 | var anchor = this.generateUniqueId(el); 44 | el.id = anchor; 45 | return anchor; 46 | } 47 | }, 48 | 49 | createNavList: function() { 50 | return $(''); 51 | }, 52 | 53 | createChildNavList: function($parent) { 54 | var $childList = this.createNavList(); 55 | $parent.append($childList); 56 | return $childList; 57 | }, 58 | 59 | generateNavEl: function(anchor, text) { 60 | var $a = $(''); 61 | $a.attr('href', '#' + anchor); 62 | $a.text(text); 63 | var $li = $('
  • '); 64 | $li.append($a); 65 | return $li; 66 | }, 67 | 68 | generateNavItem: function(headingEl) { 69 | var anchor = this.generateAnchor(headingEl); 70 | var $heading = $(headingEl); 71 | var text = $heading.data('toc-text') || $heading.text(); 72 | return this.generateNavEl(anchor, text); 73 | }, 74 | 75 | // Find the first heading level (`

    `, then `

    `, etc.) that has more than one element. Defaults to 1 (for `

    `). 76 | getTopLevel: function($scope) { 77 | for (var i = 1; i <= 6; i++) { 78 | var $headings = this.findOrFilter($scope, 'h' + i); 79 | if ($headings.length > 1) { 80 | return i; 81 | } 82 | } 83 | 84 | return 1; 85 | }, 86 | 87 | // returns the elements for the top level, and the next below it 88 | getHeadings: function($scope, topLevel) { 89 | var topSelector = 'h' + topLevel; 90 | 91 | var secondaryLevel = topLevel + 1; 92 | var secondarySelector = 'h' + secondaryLevel; 93 | 94 | return this.findOrFilter($scope, topSelector + ',' + secondarySelector); 95 | }, 96 | 97 | getNavLevel: function(el) { 98 | return parseInt(el.tagName.charAt(1), 10); 99 | }, 100 | 101 | populateNav: function($topContext, topLevel, $headings) { 102 | var $context = $topContext; 103 | var $prevNav; 104 | 105 | var helpers = this; 106 | $headings.each(function(i, el) { 107 | var $newNav = helpers.generateNavItem(el); 108 | var navLevel = helpers.getNavLevel(el); 109 | 110 | // determine the proper $context 111 | if (navLevel === topLevel) { 112 | // use top level 113 | $context = $topContext; 114 | } else if ($prevNav && $context === $topContext) { 115 | // create a new level of the tree and switch to it 116 | $context = helpers.createChildNavList($prevNav); 117 | } // else use the current $context 118 | 119 | $context.append($newNav); 120 | 121 | $prevNav = $newNav; 122 | }); 123 | }, 124 | 125 | parseOps: function(arg) { 126 | var opts; 127 | if (arg.jquery) { 128 | opts = { 129 | $nav: arg 130 | }; 131 | } else { 132 | opts = arg; 133 | } 134 | opts.$scope = opts.$scope || $(document.body); 135 | return opts; 136 | } 137 | }, 138 | 139 | // accepts a jQuery object, or an options object 140 | init: function(opts) { 141 | opts = this.helpers.parseOps(opts); 142 | 143 | // ensure that the data attribute is in place for styling 144 | opts.$nav.attr('data-toggle', 'toc'); 145 | 146 | var $topContext = this.helpers.createChildNavList(opts.$nav); 147 | var topLevel = this.helpers.getTopLevel(opts.$scope); 148 | var $headings = this.helpers.getHeadings(opts.$scope, topLevel); 149 | this.helpers.populateNav($topContext, topLevel, $headings); 150 | } 151 | }; 152 | 153 | $(function() { 154 | $('nav[data-toggle="toc"]').each(function(i, el) { 155 | var $nav = $(el); 156 | Toc.init($nav); 157 | }); 158 | }); 159 | })(); 160 | -------------------------------------------------------------------------------- /docs/card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcnorris/precautionary/a0019fc6baaa0a01ce1cef1b75982fdd7ae52d80/docs/card.png -------------------------------------------------------------------------------- /docs/docsearch.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | 3 | // register a handler to move the focus to the search bar 4 | // upon pressing shift + "/" (i.e. "?") 5 | $(document).on('keydown', function(e) { 6 | if (e.shiftKey && e.keyCode == 191) { 7 | e.preventDefault(); 8 | $("#search-input").focus(); 9 | } 10 | }); 11 | 12 | $(document).ready(function() { 13 | // do keyword highlighting 14 | /* modified from https://jsfiddle.net/julmot/bL6bb5oo/ */ 15 | var mark = function() { 16 | 17 | var referrer = document.URL ; 18 | var paramKey = "q" ; 19 | 20 | if (referrer.indexOf("?") !== -1) { 21 | var qs = referrer.substr(referrer.indexOf('?') + 1); 22 | var qs_noanchor = qs.split('#')[0]; 23 | var qsa = qs_noanchor.split('&'); 24 | var keyword = ""; 25 | 26 | for (var i = 0; i < qsa.length; i++) { 27 | var currentParam = qsa[i].split('='); 28 | 29 | if (currentParam.length !== 2) { 30 | continue; 31 | } 32 | 33 | if (currentParam[0] == paramKey) { 34 | keyword = decodeURIComponent(currentParam[1].replace(/\+/g, "%20")); 35 | } 36 | } 37 | 38 | if (keyword !== "") { 39 | $(".contents").unmark({ 40 | done: function() { 41 | $(".contents").mark(keyword); 42 | } 43 | }); 44 | } 45 | } 46 | }; 47 | 48 | mark(); 49 | }); 50 | }); 51 | 52 | /* Search term highlighting ------------------------------*/ 53 | 54 | function matchedWords(hit) { 55 | var words = []; 56 | 57 | var hierarchy = hit._highlightResult.hierarchy; 58 | // loop to fetch from lvl0, lvl1, etc. 59 | for (var idx in hierarchy) { 60 | words = words.concat(hierarchy[idx].matchedWords); 61 | } 62 | 63 | var content = hit._highlightResult.content; 64 | if (content) { 65 | words = words.concat(content.matchedWords); 66 | } 67 | 68 | // return unique words 69 | var words_uniq = [...new Set(words)]; 70 | return words_uniq; 71 | } 72 | 73 | function updateHitURL(hit) { 74 | 75 | var words = matchedWords(hit); 76 | var url = ""; 77 | 78 | if (hit.anchor) { 79 | url = hit.url_without_anchor + '?q=' + escape(words.join(" ")) + '#' + hit.anchor; 80 | } else { 81 | url = hit.url + '?q=' + escape(words.join(" ")); 82 | } 83 | 84 | return url; 85 | } 86 | -------------------------------------------------------------------------------- /docs/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcnorris/precautionary/a0019fc6baaa0a01ce1cef1b75982fdd7ae52d80/docs/favicon-16x16.png -------------------------------------------------------------------------------- /docs/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcnorris/precautionary/a0019fc6baaa0a01ce1cef1b75982fdd7ae52d80/docs/favicon-32x32.png -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcnorris/precautionary/a0019fc6baaa0a01ce1cef1b75982fdd7ae52d80/docs/favicon.ico -------------------------------------------------------------------------------- /docs/link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /docs/logo.svg: -------------------------------------------------------------------------------- 1 | image/svg+xmlCAUTIONPREARY -------------------------------------------------------------------------------- /docs/pkgdown.js: -------------------------------------------------------------------------------- 1 | /* http://gregfranko.com/blog/jquery-best-practices/ */ 2 | (function($) { 3 | $(function() { 4 | 5 | $('.navbar-fixed-top').headroom(); 6 | 7 | $('body').css('padding-top', $('.navbar').height() + 10); 8 | $(window).resize(function(){ 9 | $('body').css('padding-top', $('.navbar').height() + 10); 10 | }); 11 | 12 | $('[data-toggle="tooltip"]').tooltip(); 13 | 14 | var cur_path = paths(location.pathname); 15 | var links = $("#navbar ul li a"); 16 | var max_length = -1; 17 | var pos = -1; 18 | for (var i = 0; i < links.length; i++) { 19 | if (links[i].getAttribute("href") === "#") 20 | continue; 21 | // Ignore external links 22 | if (links[i].host !== location.host) 23 | continue; 24 | 25 | var nav_path = paths(links[i].pathname); 26 | 27 | var length = prefix_length(nav_path, cur_path); 28 | if (length > max_length) { 29 | max_length = length; 30 | pos = i; 31 | } 32 | } 33 | 34 | // Add class to parent
  • , and enclosing
  • if in dropdown 35 | if (pos >= 0) { 36 | var menu_anchor = $(links[pos]); 37 | menu_anchor.parent().addClass("active"); 38 | menu_anchor.closest("li.dropdown").addClass("active"); 39 | } 40 | }); 41 | 42 | function paths(pathname) { 43 | var pieces = pathname.split("/"); 44 | pieces.shift(); // always starts with / 45 | 46 | var end = pieces[pieces.length - 1]; 47 | if (end === "index.html" || end === "") 48 | pieces.pop(); 49 | return(pieces); 50 | } 51 | 52 | // Returns -1 if not found 53 | function prefix_length(needle, haystack) { 54 | if (needle.length > haystack.length) 55 | return(-1); 56 | 57 | // Special case for length-0 haystack, since for loop won't run 58 | if (haystack.length === 0) { 59 | return(needle.length === 0 ? 0 : -1); 60 | } 61 | 62 | for (var i = 0; i < haystack.length; i++) { 63 | if (needle[i] != haystack[i]) 64 | return(i); 65 | } 66 | 67 | return(haystack.length); 68 | } 69 | 70 | /* Clipboard --------------------------*/ 71 | 72 | function changeTooltipMessage(element, msg) { 73 | var tooltipOriginalTitle=element.getAttribute('data-original-title'); 74 | element.setAttribute('data-original-title', msg); 75 | $(element).tooltip('show'); 76 | element.setAttribute('data-original-title', tooltipOriginalTitle); 77 | } 78 | 79 | if(ClipboardJS.isSupported()) { 80 | $(document).ready(function() { 81 | var copyButton = ""; 82 | 83 | $("div.sourceCode").addClass("hasCopyButton"); 84 | 85 | // Insert copy buttons: 86 | $(copyButton).prependTo(".hasCopyButton"); 87 | 88 | // Initialize tooltips: 89 | $('.btn-copy-ex').tooltip({container: 'body'}); 90 | 91 | // Initialize clipboard: 92 | var clipboardBtnCopies = new ClipboardJS('[data-clipboard-copy]', { 93 | text: function(trigger) { 94 | return trigger.parentNode.textContent.replace(/\n#>[^\n]*/g, ""); 95 | } 96 | }); 97 | 98 | clipboardBtnCopies.on('success', function(e) { 99 | changeTooltipMessage(e.trigger, 'Copied!'); 100 | e.clearSelection(); 101 | }); 102 | 103 | clipboardBtnCopies.on('error', function() { 104 | changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy'); 105 | }); 106 | }); 107 | } 108 | })(window.jQuery || window.$) 109 | -------------------------------------------------------------------------------- /docs/pkgdown.yml: -------------------------------------------------------------------------------- 1 | pandoc: 2.9.2.1 2 | pkgdown: 2.0.2 3 | pkgdown_sha: ~ 4 | articles: 5 | DTP-vs-Korn94: DTP-vs-Korn94.html 6 | FDA-proactive: FDA-proactive.html 7 | Intro: Intro.html 8 | MCSE-Free: MCSE-Free.html 9 | Safety-Schematic-via-CPE: Safety-Schematic-via-CPE.html 10 | last_built: 2022-02-01T13:43Z 11 | urls: 12 | reference: https://dcnorris.github.io/precautionary/reference 13 | article: https://dcnorris.github.io/precautionary/articles 14 | 15 | -------------------------------------------------------------------------------- /docs/reference/Rplot001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcnorris/precautionary/a0019fc6baaa0a01ce1cef1b75982fdd7ae52d80/docs/reference/Rplot001.png -------------------------------------------------------------------------------- /docs/reference/figures/card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcnorris/precautionary/a0019fc6baaa0a01ce1cef1b75982fdd7ae52d80/docs/reference/figures/card.png -------------------------------------------------------------------------------- /docs/reference/figures/logo.svg: -------------------------------------------------------------------------------- 1 | image/svg+xmlCAUTIONPREARY -------------------------------------------------------------------------------- /docs/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | https://dcnorris.github.io/precautionary/404.html 5 | 6 | 7 | https://dcnorris.github.io/precautionary/LICENSE-text.html 8 | 9 | 10 | https://dcnorris.github.io/precautionary/articles/DTP-vs-Korn94.html 11 | 12 | 13 | https://dcnorris.github.io/precautionary/articles/FDA-proactive.html 14 | 15 | 16 | https://dcnorris.github.io/precautionary/articles/Intro.html 17 | 18 | 19 | https://dcnorris.github.io/precautionary/articles/MCSE-Free.html 20 | 21 | 22 | https://dcnorris.github.io/precautionary/articles/Safety-Schematic-via-CPE.html 23 | 24 | 25 | https://dcnorris.github.io/precautionary/articles/index.html 26 | 27 | 28 | https://dcnorris.github.io/precautionary/authors.html 29 | 30 | 31 | https://dcnorris.github.io/precautionary/index.html 32 | 33 | 34 | https://dcnorris.github.io/precautionary/news/index.html 35 | 36 | 37 | https://dcnorris.github.io/precautionary/reference/Boin-class.html 38 | 39 | 40 | https://dcnorris.github.io/precautionary/reference/Ccd-class.html 41 | 42 | 43 | https://dcnorris.github.io/precautionary/reference/Cpe-class.html 44 | 45 | 46 | https://dcnorris.github.io/precautionary/reference/Cpe3_3-class.html 47 | 48 | 49 | https://dcnorris.github.io/precautionary/reference/Crm-class.html 50 | 51 | 52 | https://dcnorris.github.io/precautionary/reference/HyperMTDi-class.html 53 | 54 | 55 | https://dcnorris.github.io/precautionary/reference/applied_crm.html 56 | 57 | 58 | https://dcnorris.github.io/precautionary/reference/as.data.table.exact.html 59 | 60 | 61 | https://dcnorris.github.io/precautionary/reference/as.data.table.precautionary.html 62 | 63 | 64 | https://dcnorris.github.io/precautionary/reference/calculate_dtps.html 65 | 66 | 67 | https://dcnorris.github.io/precautionary/reference/cohorts_of_n.html 68 | 69 | 70 | https://dcnorris.github.io/precautionary/reference/crm.html 71 | 72 | 73 | https://dcnorris.github.io/precautionary/reference/crmh.html 74 | 75 | 76 | https://dcnorris.github.io/precautionary/reference/crmh_xo.html 77 | 78 | 79 | https://dcnorris.github.io/precautionary/reference/exact.html 80 | 81 | 82 | https://dcnorris.github.io/precautionary/reference/extend.html 83 | 84 | 85 | https://dcnorris.github.io/precautionary/reference/format.safetytab.html 86 | 87 | 88 | https://dcnorris.github.io/precautionary/reference/hyper_mtdi_lognormal-class.html 89 | 90 | 91 | https://dcnorris.github.io/precautionary/reference/index.html 92 | 93 | 94 | https://dcnorris.github.io/precautionary/reference/mtdi_lognormal-class.html 95 | 96 | 97 | https://dcnorris.github.io/precautionary/reference/ordinalizer.html 98 | 99 | 100 | https://dcnorris.github.io/precautionary/reference/phase1_sim.html 101 | 102 | 103 | https://dcnorris.github.io/precautionary/reference/plan.html 104 | 105 | 106 | https://dcnorris.github.io/precautionary/reference/plot-mtdi_distribution-ANY-method.html 107 | 108 | 109 | https://dcnorris.github.io/precautionary/reference/plot-mtdi_generator-ANY-method.html 110 | 111 | 112 | https://dcnorris.github.io/precautionary/reference/plot_dutycycle.html 113 | 114 | 115 | https://dcnorris.github.io/precautionary/reference/precautionary-package.html 116 | 117 | 118 | https://dcnorris.github.io/precautionary/reference/print.exact.html 119 | 120 | 121 | https://dcnorris.github.io/precautionary/reference/print.hyper.html 122 | 123 | 124 | https://dcnorris.github.io/precautionary/reference/print.precautionary.html 125 | 126 | 127 | https://dcnorris.github.io/precautionary/reference/safety_kable.html 128 | 129 | 130 | https://dcnorris.github.io/precautionary/reference/simulate_trials.html 131 | 132 | 133 | https://dcnorris.github.io/precautionary/reference/simulation_function.u_i.html 134 | 135 | 136 | https://dcnorris.github.io/precautionary/reference/stop_for_excess_toxicity_empiric.html 137 | 138 | 139 | https://dcnorris.github.io/precautionary/reference/summary.exact.html 140 | 141 | 142 | https://dcnorris.github.io/precautionary/reference/summary.precautionary.html 143 | 144 | 145 | https://dcnorris.github.io/precautionary/reference/test_draw_samples.html 146 | 147 | 148 | https://dcnorris.github.io/precautionary/reference/viola_dtp.html 149 | 150 | 151 | -------------------------------------------------------------------------------- /exec/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: scryer sicstus scryer_tabs sicstus_tabs sysdata 2 | 3 | scryer: scryer_tabs sysdata 4 | 5 | sicstus: sicstus_tabs sysdata 6 | 7 | sysdata : T2.tab T3.tab T4.tab T5.tab T6.tab T7.tab T8.tab make_sysdata_TUb.R 8 | Rscript make_sysdata_TUb.R 9 | 10 | scryer_tabs : scryer.pl esc.pl 11 | scryer-prolog scryer.pl esc.pl 12 | 13 | sicstus_tabs : sicstus.pl esc.pl 14 | sicstus -l sicstus.pl -l esc.pl 15 | 16 | benchmark: 17 | scryer-prolog --version 18 | time scryer-prolog scryer.pl esc.pl 19 | -------------------------------------------------------------------------------- /exec/T2.tab: -------------------------------------------------------------------------------- 1 | 0 0 2 | NA 0 3 | 0 0 4 | NA 1 5 | 0 0 6 | 0 2 7 | 0 0 8 | 1 2 9 | 0 0 10 | 2 2 11 | 0 0 12 | 3 2 13 | 0 0 14 | 0 3 15 | 0 0 16 | 1 3 17 | 0 0 18 | 2 3 19 | 0 0 20 | 3 3 21 | 0 1 22 | NA 0 23 | 0 1 24 | 0 1 25 | 0 1 26 | 1 1 27 | 0 1 28 | 2 1 29 | 0 1 30 | 3 1 31 | 0 1 32 | 0 2 33 | 0 1 34 | 1 2 35 | 0 1 36 | 2 2 37 | 0 1 38 | 3 2 39 | 0 1 40 | 0 3 41 | 0 1 42 | 1 3 43 | 0 1 44 | 2 3 45 | 0 1 46 | 3 3 47 | 0 2 48 | 0 NA 49 | 0 2 50 | 1 NA 51 | 0 2 52 | 2 NA 53 | 0 2 54 | 3 NA 55 | 0 3 56 | 0 NA 57 | 0 3 58 | 1 NA 59 | 0 3 60 | 2 NA 61 | 0 3 62 | 3 NA 63 | 1 0 64 | 0 0 65 | 1 0 66 | 0 1 67 | 1 0 68 | 0 2 69 | 1 0 70 | 0 3 71 | 1 1 72 | 0 0 73 | 1 1 74 | 0 1 75 | 1 1 76 | 0 2 77 | 1 1 78 | 0 3 79 | 1 2 80 | 0 NA 81 | 1 3 82 | 0 NA 83 | 1 NA 84 | 1 NA 85 | 1 NA 86 | 2 NA 87 | 1 NA 88 | 3 NA 89 | 2 NA 90 | NA NA 91 | 3 NA 92 | NA NA 93 | -------------------------------------------------------------------------------- /exec/T3.tab: -------------------------------------------------------------------------------- 1 | 0 0 0 2 | NA NA 0 3 | 0 0 0 4 | NA NA 1 5 | 0 0 0 6 | NA 0 2 7 | 0 0 0 8 | NA 1 2 9 | 0 0 0 10 | 0 2 2 11 | 0 0 0 12 | 1 2 2 13 | 0 0 0 14 | 2 2 2 15 | 0 0 0 16 | 3 2 2 17 | 0 0 0 18 | 0 3 2 19 | 0 0 0 20 | 1 3 2 21 | 0 0 0 22 | 2 3 2 23 | 0 0 0 24 | 3 3 2 25 | 0 0 0 26 | NA 0 3 27 | 0 0 0 28 | NA 1 3 29 | 0 0 0 30 | 0 2 3 31 | 0 0 0 32 | 1 2 3 33 | 0 0 0 34 | 2 2 3 35 | 0 0 0 36 | 3 2 3 37 | 0 0 0 38 | 0 3 3 39 | 0 0 0 40 | 1 3 3 41 | 0 0 0 42 | 2 3 3 43 | 0 0 0 44 | 3 3 3 45 | 0 0 1 46 | NA NA 0 47 | 0 0 1 48 | NA 0 1 49 | 0 0 1 50 | NA 1 1 51 | 0 0 1 52 | 0 2 1 53 | 0 0 1 54 | 1 2 1 55 | 0 0 1 56 | 2 2 1 57 | 0 0 1 58 | 3 2 1 59 | 0 0 1 60 | 0 3 1 61 | 0 0 1 62 | 1 3 1 63 | 0 0 1 64 | 2 3 1 65 | 0 0 1 66 | 3 3 1 67 | 0 0 1 68 | NA 0 2 69 | 0 0 1 70 | NA 1 2 71 | 0 0 1 72 | 0 2 2 73 | 0 0 1 74 | 1 2 2 75 | 0 0 1 76 | 2 2 2 77 | 0 0 1 78 | 3 2 2 79 | 0 0 1 80 | 0 3 2 81 | 0 0 1 82 | 1 3 2 83 | 0 0 1 84 | 2 3 2 85 | 0 0 1 86 | 3 3 2 87 | 0 0 1 88 | NA 0 3 89 | 0 0 1 90 | NA 1 3 91 | 0 0 1 92 | 0 2 3 93 | 0 0 1 94 | 1 2 3 95 | 0 0 1 96 | 2 2 3 97 | 0 0 1 98 | 3 2 3 99 | 0 0 1 100 | 0 3 3 101 | 0 0 1 102 | 1 3 3 103 | 0 0 1 104 | 2 3 3 105 | 0 0 1 106 | 3 3 3 107 | 0 0 2 108 | NA 0 NA 109 | 0 0 2 110 | NA 1 NA 111 | 0 0 2 112 | 0 2 NA 113 | 0 0 2 114 | 1 2 NA 115 | 0 0 2 116 | 2 2 NA 117 | 0 0 2 118 | 3 2 NA 119 | 0 0 2 120 | 0 3 NA 121 | 0 0 2 122 | 1 3 NA 123 | 0 0 2 124 | 2 3 NA 125 | 0 0 2 126 | 3 3 NA 127 | 0 0 3 128 | NA 0 NA 129 | 0 0 3 130 | NA 1 NA 131 | 0 0 3 132 | 0 2 NA 133 | 0 0 3 134 | 1 2 NA 135 | 0 0 3 136 | 2 2 NA 137 | 0 0 3 138 | 3 2 NA 139 | 0 0 3 140 | 0 3 NA 141 | 0 0 3 142 | 1 3 NA 143 | 0 0 3 144 | 2 3 NA 145 | 0 0 3 146 | 3 3 NA 147 | 0 1 0 148 | NA 0 0 149 | 0 1 0 150 | NA 0 1 151 | 0 1 0 152 | NA 0 2 153 | 0 1 0 154 | NA 0 3 155 | 0 1 1 156 | NA 0 0 157 | 0 1 1 158 | NA 0 1 159 | 0 1 1 160 | NA 0 2 161 | 0 1 1 162 | NA 0 3 163 | 0 1 2 164 | NA 0 NA 165 | 0 1 3 166 | NA 0 NA 167 | 0 1 NA 168 | 0 1 NA 169 | 0 1 NA 170 | 1 1 NA 171 | 0 1 NA 172 | 2 1 NA 173 | 0 1 NA 174 | 3 1 NA 175 | 0 1 NA 176 | 0 2 NA 177 | 0 1 NA 178 | 1 2 NA 179 | 0 1 NA 180 | 2 2 NA 181 | 0 1 NA 182 | 3 2 NA 183 | 0 1 NA 184 | 0 3 NA 185 | 0 1 NA 186 | 1 3 NA 187 | 0 1 NA 188 | 2 3 NA 189 | 0 1 NA 190 | 3 3 NA 191 | 0 2 NA 192 | 0 NA NA 193 | 0 2 NA 194 | 1 NA NA 195 | 0 2 NA 196 | 2 NA NA 197 | 0 2 NA 198 | 3 NA NA 199 | 0 3 NA 200 | 0 NA NA 201 | 0 3 NA 202 | 1 NA NA 203 | 0 3 NA 204 | 2 NA NA 205 | 0 3 NA 206 | 3 NA NA 207 | 1 0 0 208 | 0 NA 0 209 | 1 0 0 210 | 0 NA 1 211 | 1 0 0 212 | 0 0 2 213 | 1 0 0 214 | 0 1 2 215 | 1 0 0 216 | 0 2 2 217 | 1 0 0 218 | 0 3 2 219 | 1 0 0 220 | 0 0 3 221 | 1 0 0 222 | 0 1 3 223 | 1 0 0 224 | 0 2 3 225 | 1 0 0 226 | 0 3 3 227 | 1 0 1 228 | 0 NA 0 229 | 1 0 1 230 | 0 0 1 231 | 1 0 1 232 | 0 1 1 233 | 1 0 1 234 | 0 2 1 235 | 1 0 1 236 | 0 3 1 237 | 1 0 1 238 | 0 0 2 239 | 1 0 1 240 | 0 1 2 241 | 1 0 1 242 | 0 2 2 243 | 1 0 1 244 | 0 3 2 245 | 1 0 1 246 | 0 0 3 247 | 1 0 1 248 | 0 1 3 249 | 1 0 1 250 | 0 2 3 251 | 1 0 1 252 | 0 3 3 253 | 1 0 2 254 | 0 0 NA 255 | 1 0 2 256 | 0 1 NA 257 | 1 0 2 258 | 0 2 NA 259 | 1 0 2 260 | 0 3 NA 261 | 1 0 3 262 | 0 0 NA 263 | 1 0 3 264 | 0 1 NA 265 | 1 0 3 266 | 0 2 NA 267 | 1 0 3 268 | 0 3 NA 269 | 1 1 0 270 | 0 0 0 271 | 1 1 0 272 | 0 0 1 273 | 1 1 0 274 | 0 0 2 275 | 1 1 0 276 | 0 0 3 277 | 1 1 1 278 | 0 0 0 279 | 1 1 1 280 | 0 0 1 281 | 1 1 1 282 | 0 0 2 283 | 1 1 1 284 | 0 0 3 285 | 1 1 2 286 | 0 0 NA 287 | 1 1 3 288 | 0 0 NA 289 | 1 1 NA 290 | 0 1 NA 291 | 1 1 NA 292 | 0 2 NA 293 | 1 1 NA 294 | 0 3 NA 295 | 1 2 NA 296 | 0 NA NA 297 | 1 3 NA 298 | 0 NA NA 299 | 1 NA NA 300 | 1 NA NA 301 | 1 NA NA 302 | 2 NA NA 303 | 1 NA NA 304 | 3 NA NA 305 | 2 NA NA 306 | NA NA NA 307 | 3 NA NA 308 | NA NA NA 309 | -------------------------------------------------------------------------------- /exec/make_sysdata_TUb.R: -------------------------------------------------------------------------------- 1 | ## Make the internal data {A, U, b} required for exact simulation of 3+3 design 2 | 3 | T <- U <- b <- list() 4 | for(D in 2:8){ 5 | T_raw <- read.table(paste0("T", D, ".tab")) 6 | J <- nrow(T_raw)/2 7 | T[[D]] <- aperm(array(as.matrix(T_raw), dim = c(2, J, D) 8 | , dimnames = list(c = 1:2, j = NULL, d = paste0("D",1:D))) 9 | , perm = c("c","d","j")) 10 | U[[D]] <- cbind(apply(T[[D]], c("j","d"), sum, na.rm=TRUE), 11 | apply(3 - T[[D]], c("j","d"), sum, na.rm=TRUE)) 12 | dimnames(U[[D]]) <- list(j = NULL, pq = c(paste0("D", rep(1:D, 2)))) 13 | b[[D]] <- apply(log(choose(3, T[[D]])), "j", sum, na.rm=TRUE) 14 | } 15 | 16 | usethis::use_data(T, U, b, 17 | internal = TRUE, 18 | overwrite = TRUE) 19 | -------------------------------------------------------------------------------- /exec/prolog/BOIN25-2-6-24.tab: -------------------------------------------------------------------------------- 1 | 2 0 1 0 6 2 | 2 0 1 1 6 3 | 2 0 1 1 6 4 | 1 0 2 2 6 5 | 0 1 2 2 6 6 | 2 0 1 1 6 7 | 1 0 2 2 6 8 | 0 1 2 2 6 9 | 1 0 3 2 6 10 | 0 1 3 2 6 11 | 1 0 3 3 6 12 | 0 1 3 3 6 13 | 0 1 2 2 5 14 | 2 0 2 1 6 15 | 1 0 3 2 6 16 | 0 1 3 2 6 17 | 1 0 4 2 6 18 | 1 1 6 2 6 19 | 0 2 6 2 6 20 | 0 2 5 2 6 21 | 1 0 4 3 6 22 | 1 1 6 3 6 23 | 0 2 6 3 6 24 | 0 2 5 3 6 25 | 0 1 3 2 5 26 | 1 0 5 2 6 27 | 1 1 6 2 6 28 | 0 2 6 2 6 29 | 1 0 5 3 6 30 | 1 1 6 3 6 31 | 0 2 6 3 6 32 | 1 1 6 2 6 33 | 1 1 6 3 6 34 | 0 2 6 2 5 35 | 0 2 5 2 5 36 | 1 0 6 3 5 37 | 1 1 6 3 5 38 | 1 1 6 3 5 39 | 0 2 6 3 5 40 | 1 1 6 3 5 41 | 0 2 6 3 5 42 | 0 2 5 3 5 43 | 0 1 3 2 4 44 | 0 1 2 1 3 45 | 2 0 3 1 6 46 | 1 0 4 2 6 47 | 1 1 6 2 6 48 | 0 2 6 2 6 49 | 0 2 5 2 6 50 | 1 0 5 2 6 51 | 1 1 6 2 6 52 | 0 2 6 2 6 53 | 1 0 5 3 6 54 | 1 1 6 3 6 55 | 0 2 6 3 6 56 | 1 1 6 2 6 57 | 1 1 6 3 6 58 | 0 2 6 2 5 59 | 0 2 5 2 5 60 | 1 0 6 2 6 61 | 1 1 6 2 6 62 | 1 0 6 3 6 63 | 1 1 6 3 6 64 | 1 1 6 2 6 65 | 1 1 6 3 6 66 | 0 2 6 2 5 67 | 1 0 6 3 5 68 | 1 1 6 3 5 69 | 1 1 6 3 5 70 | 0 2 6 3 5 71 | 1 1 6 2 5 72 | 1 1 6 3 5 73 | 0 2 6 2 4 74 | 0 2 5 2 4 75 | 0 1 3 1 3 76 | 1 0 6 2 6 77 | 1 1 6 2 6 78 | 1 0 6 3 6 79 | 1 1 6 3 6 80 | 1 1 6 2 6 81 | 1 1 6 3 6 82 | 0 2 6 2 5 83 | 1 0 6 3 5 84 | 1 1 6 3 5 85 | 1 1 6 3 5 86 | 0 2 6 3 5 87 | 1 1 6 2 5 88 | 1 1 6 3 5 89 | 0 2 6 2 4 90 | 0 2 5 2 4 91 | 1 0 6 3 4 92 | 1 1 6 3 4 93 | 1 1 6 3 4 94 | 0 2 6 3 4 95 | 1 1 6 3 4 96 | 0 2 6 3 4 97 | 0 2 5 3 4 98 | 0 1 3 2 3 99 | 0 1 2 1 2 100 | 2 0 4 1 6 101 | 1 0 5 2 6 102 | 1 1 6 2 6 103 | 0 2 6 2 6 104 | 1 0 6 2 6 105 | 1 1 6 2 6 106 | 1 0 6 3 6 107 | 1 1 6 3 6 108 | 1 1 6 2 6 109 | 1 1 6 3 6 110 | 0 2 6 2 5 111 | 1 0 6 2 6 112 | 1 0 6 3 6 113 | 1 1 6 2 6 114 | 1 1 6 3 6 115 | 1 0 6 3 5 116 | 1 1 6 3 5 117 | 1 1 6 2 5 118 | 1 1 6 3 5 119 | 0 2 6 2 4 120 | 2 1 6 1 6 121 | 1 1 6 2 6 122 | 1 1 6 2 5 123 | 1 1 6 2 4 124 | 0 2 6 1 3 125 | 0 2 5 1 3 126 | 1 0 6 2 6 127 | 1 0 6 3 6 128 | 1 1 6 2 6 129 | 1 1 6 3 6 130 | 1 0 6 3 5 131 | 1 1 6 3 5 132 | 1 1 6 2 5 133 | 1 1 6 3 5 134 | 0 2 6 2 4 135 | 1 0 6 3 4 136 | 1 1 6 3 4 137 | 1 1 6 3 4 138 | 0 2 6 3 4 139 | 1 1 6 2 4 140 | 1 1 6 3 4 141 | 0 2 6 2 3 142 | 0 2 5 2 3 143 | 0 1 3 1 2 144 | 1 0 6 2 6 145 | 1 0 6 3 6 146 | 1 1 6 2 6 147 | 1 1 6 3 6 148 | 1 0 6 3 5 149 | 1 1 6 3 5 150 | 1 1 6 2 5 151 | 1 1 6 3 5 152 | 0 2 6 2 4 153 | 1 0 6 3 4 154 | 1 1 6 3 4 155 | 1 1 6 3 4 156 | 0 2 6 3 4 157 | 1 1 6 2 4 158 | 1 1 6 3 4 159 | 0 2 6 2 3 160 | 0 2 5 2 3 161 | 1 0 6 3 3 162 | 1 1 6 3 3 163 | 1 1 6 3 3 164 | 0 2 6 3 3 165 | 1 1 6 3 3 166 | 0 2 6 3 3 167 | 0 2 5 3 3 168 | 0 1 3 2 2 169 | 0 1 2 1 1 170 | 0 1 1 0 0 171 | -------------------------------------------------------------------------------- /exec/prolog/benchmarking.pl: -------------------------------------------------------------------------------- 1 | % Module of benchmarking utilities 2 | 3 | :- module(benchmarking, [ 4 | version/1, 5 | time/2, 6 | seconds_since/2, 7 | minutes_since/2 8 | ]). 9 | 10 | version(Version) :- 11 | '$scryer_prolog_version'(Version). 12 | 13 | %% The following adapted from @triska's time:time/1 14 | :- meta_predicate time(0, -). 15 | 16 | time(Goal, Elapsed) :- 17 | '$cpu_now'(T0), 18 | ( Goal, 19 | seconds_since(Elapsed, T0) 20 | ; seconds_since(Elapsed, T0) 21 | ). 22 | 23 | since_elapsed(T0, Elapsed) :- 24 | '$cpu_now'(T), 25 | Elapsed is T - T0. 26 | 27 | seconds_since(Seconds, T0) :- 28 | '$cpu_now'(T), 29 | Seconds is T - T0. 30 | 31 | minutes_since(Minutes, T0) :- 32 | seconds_since(Seconds, T0), 33 | Minutes is Seconds/60.0. 34 | -------------------------------------------------------------------------------- /exec/prolog/boin.R: -------------------------------------------------------------------------------- 1 | ## Decision boundaries for 'local BOIN' with pi[0,j] = pi[1,j] = pi[2,j], 2 | ## defaulting to the recommended phi_1/phi = 0.6, phi_2/phi = 1.4 3 | 4 | boin_lambda <- function(phi, delta = c(-0.4, 0.4)) { 5 | phi_ <- (1 + delta) * phi 6 | 7 | inv_lambda <- 1 - log(1 + delta)/log((1 - phi_)/(1 - phi)) 8 | 1/inv_lambda 9 | } 10 | 11 | tabulate_boin_lambdas <- function(phi = seq(0.15, 0.3, 0.05)) { 12 | for (p in phi) 13 | print(fractions(boin_lambda(p))) 14 | } 15 | 16 | ## The 5% quantile of Beta(x+1, o+1) is the value of phi we are 17 | ## "95% confident" is exceeded at a dose with tally x/(x+o), 18 | ## given a Bayes-Laplace prior B(1,1) is used. 19 | predicate_qbeta05 <- function(nmax=14) { 20 | for (n in 1:nmax) { 21 | for (x in 1:n) { 22 | q <- qbeta(p = 0.05, shape1 = x+1, shape2 = n-x+1) 23 | cat(paste0("qbeta05_alpha_beta(", fractions(q),", ", x+1, ", ", n-x+1, "). % ", q, "\n")) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /exec/prolog/ccd_check.pl: -------------------------------------------------------------------------------- 1 | %% Prototyping some checks of CPE ... 2 | 3 | :- use_module(ccd). 4 | 5 | :- use_module(library(lambda)). 6 | 7 | %% Read path 'matrices' from a file, to speed testing... 8 | paths_j(Ms, J) :- 9 | open("testD2", read, Stream), 10 | read_term(Stream, Ms, []), % Ms were generated with ccd:default_ccd(CCD), D=2. 11 | length(Ms, J). 12 | 13 | %% TODO: Implement checks derived from the condition 𝚺ⱼ 𝜋ⱼ ≡ 1 14 | path_probs_sum_1(Paths, Qjd, Njd, Nj_, MaxN) :- 15 | %% TODO: Once this matrix notation 'settles down', it might be nice 16 | %% to consider how goal expansions might implement a cleaner 17 | %% notation. 18 | % 1. Extract dose-wise tallies as a matrix 19 | maplist(\Path^Qd^( % (Qd) for a length-D list of tallies Q 20 | Path = (Ls^Rs^Es~>_), foldl(append, [Ls,Rs,Es], [], Qd) 21 | ), Paths, Qjd), % (Qjd) is a row-major J*D matrix (J-list of D-lists) 22 | % 2. Obtain J*D matrices (N|T|U)dj, dose-wise lists of path-wise (enrollment|tox|no-tox) 23 | maplist(\Qd^Nd^Td^Ud^( 24 | maplist(\Q^N^T^U^( 25 | Q=T/N, U #= N-T 26 | ), Qd, Nd, Td, Ud) % length-D lists (as if we 'attached' a 'd' index) 27 | ), Qjd, Njd, Tjd, Ujd), % now length-J lists of length-D lists 28 | % 3. Sum over d index for j-indexed (path-wise) totals 29 | maplist(\Nd^N_^( % does underscore serve well to denote a summed-over index? 30 | sum(Nd, #=, N_) 31 | ), Njd, Nj_), % Nj_ = 𝚺_d Njd ∀ j 32 | % 4. Obtain maxⱼ(Nⱼ) over all paths (needed below to avoid fractions in test) 33 | foldl(\A^B^MaxAB^( 34 | MaxAB #= max(A,B) 35 | ), Nj_, 0, MaxN), 36 | % 5. Check the basic identity 𝚺ⱼ 2^(MaxN - Nⱼ) = 2^MaxN, 37 | % derived by plugging p = q = 1/2 into 𝚺ⱼ 𝛑ⱼ ≡ 1. 38 | %% Let's call the LHS terms Gdⱼ (G for deGeneracy); then ... 39 | maplist(MaxN+\N^G^( 40 | 2^(MaxN-N) #= G 41 | ), Nj_, Gj), % Gj = 2^(MaxN-Nj) ∀ j 42 | sum(Gj, #=, 2^MaxN), 43 | true. /* ~~snip~~ 44 | % 6. Check the identities 0 = 𝚺ⱼ 2^(MaxN - Nⱼ)*(Tⱼd-Uⱼd) ∀ d, 45 | % derived by taking derivative 𝜕/𝜕p (𝚺ⱼ 𝛑ⱼ ≡ 1) at p=(1/2,1/2,...1/2). 46 | */ 47 | 48 | %?- J^Qjd^Nj_^MaxN+\(paths_j(Ps, J), path_probs_sum_1(Ps, Qjd, Njd, Nj_, MaxN)). 49 | %@ J = 212, Qjd = [[0/6,0/1],[1/6,0/1],[1/6,0/1],[2/6,0/1],[1/6,0/1],[2/6,0/1],[2/6,0/1],[0/2,... / ...],[... / ...|...],...|...], Nj_ = [7,7,7,7,7,7,7,8,12,12|...], MaxN = 12. 50 | 51 | %?- t+\(paths_j(Ps, J), time(path_probs_sum_1(Ps, Qjd, Njd, Nj_, MaxN))). 52 | %@ % CPU time: 12.205 seconds 53 | %@ % CPU time: 12.209 seconds 54 | %@ true. 55 | -------------------------------------------------------------------------------- /exec/prolog/factorial.pl: -------------------------------------------------------------------------------- 1 | %% Exploration of non-monotonicity in CLP(ℤ) 2 | 3 | :- use_module(library(clpz)). 4 | :- use_module(library(error)). 5 | 6 | n_factorial(0, 1). 7 | n_factorial(N, F) :- 8 | N #> 0, 9 | N1 #= N - 1, 10 | F #= N * F1, 11 | n_factorial(N1, F1). 12 | 13 | %% A quick note about termination: 14 | 15 | %?- n_factorial(10, F). 16 | %@ F = 3628800 17 | %@ ; false. 18 | 19 | %?- time(n_factorial(N, 3628800)). 20 | %@ % CPU time: 2.179 seconds 21 | %@ N = 10 22 | %@ ; % CPU time: 2.203 seconds 23 | %@ false. % <-- NB: having found 1 solution, the program knows immediately there are none further 24 | 25 | %% Even if we ask in cases where no solution exists, the program DOES terminate: 26 | %?- time((F #= 3628801, n_factorial(N, F))). 27 | %@ % CPU time: 79.779 seconds 28 | %@ false. 29 | 30 | %% But we could offer some help to termination... 31 | %?- n_factorial(N, F), N^4 #> F. 32 | %@ N = 2, F = 2 33 | %@ ; N = 3, F = 6 34 | %@ ; N = 4, F = 24 35 | %@ ; N = 5, F = 120 36 | %@ ; N = 6, F = 720 37 | %@ ; 38 | %@ caught: error('$interrupt_thrown',repl) 39 | 40 | %% Our implementation doesn't 'know' (and can't find out) 41 | %% that N! > N^4 ∀ N > 6. But by supplying this extra info 42 | %% we can speed up termination: 43 | 44 | %?- time((N #< 7 #\/ N^4 #< F, F #= 3628801, n_factorial(N, F))). 45 | %@ % CPU time: 0.473 seconds 46 | %@ false. 47 | 48 | %% That said, let's exhibit what n_factorial/2 knows... 49 | 50 | %% Although the ordinary programmer might think this is 'pretty cool', 51 | %% for the logic programmer this is perhaps closer to the bare minimum: 52 | %% "Tell me everything that holds." 53 | 54 | %?- n_factorial(N, F). 55 | %@ N = 0, F = 1 56 | %@ ; N = 1, F = 1 57 | %@ ; N = 2, F = 2 58 | %@ ; N = 3, F = 6 59 | %@ ; N = 4, F = 24 60 | %@ ; N = 5, F = 120 61 | %@ ; N = 6, F = 720 62 | %@ ; ... 63 | 64 | %% But check THIS out! Does this not seem slightly magical? 65 | 66 | %?- n_factorial(N+2, F-1). 67 | %@ N = -1, F = 2 68 | %@ ; N = 0, F = 3 69 | %@ ; N = 1, F = 7 70 | %@ ; N = 2, F = 25 71 | %@ ; N = 3, F = 121 72 | %@ ; N = 4, F = 721 73 | %@ ; N = 5, F = 5041 74 | %@ ; ... 75 | 76 | %% But WAIT A MINUTE! Where's my N = -2, F = 2 answer? 77 | %?- N #= -2, F #= 2, n_factorial(N+2, F-1). 78 | %@ false. 79 | 80 | %?- n_factorial(-2+2, 2-1). % <-- very strong 'hints' indeed! 81 | %@ false. 82 | 83 | %% Even very strong hints don't help elicit this solution! What went wrong here? 84 | %% Should I have implemented the base case in some more general fashion? 85 | 86 | n_fact(Zero, One) :- 87 | Zero #= 0, 88 | One #= 1. 89 | n_fact(N, F) :- % identical to general clause of n_factorial/2 above 90 | N #> 0, 91 | N1 #= N - 1, 92 | F #= N * F1, 93 | n_fact(N1, F1). 94 | 95 | %?- n_fact(N+2, F-1). 96 | %@ N = -2, F = 2 % PHEW! We got it this time. 97 | %@ ; N = -1, F = 2 98 | %@ ; N = 0, F = 3 99 | %@ ; N = 1, F = 7 100 | %@ ; N = 2, F = 25 101 | %@ ; N = 3, F = 121 102 | %@ ; N = 4, F = 721 103 | %@ ; ... 104 | 105 | %% All the above was done with non-monotonic clpz: 106 | %?- clpz:monotonic. 107 | %@ false. 108 | 109 | %% So what happens if I now demand monotonicity? 110 | %?- assertz(clpz:monotonic). 111 | %@ true. 112 | 113 | %?- n_factorial(N, F). 114 | %@ N = 0, F = 1 115 | %@ ; caught: error(instantiation_error,instantiation_error(unknown(_1384246),1)) 116 | 117 | %% Oops! I forgot I would have to rewrite to avoid defaulty representation... 118 | 119 | m_factorial(0, 1). 120 | m_factorial(N, F) :- 121 | #N #> 0, 122 | #N1 #= #N - 1, 123 | #F #= #N * #F1, 124 | m_factorial(N1, F1). 125 | 126 | %?- m_factorial(N, F). 127 | %@ N = 0, F = 1 128 | %@ ; N = 1, F = 1 129 | %@ ; N = 2, F = 2 130 | %@ ; N = 3, F = 6 131 | %@ ; N = 4, F = 24 132 | %@ ; ... 133 | 134 | %% So monotonicity doesn't ruin our 'bare minimum' requirements of course. 135 | %% But do we still get the magic? 136 | 137 | %?- m_factorial(N-1, F). 138 | %@ caught: error(type_error(integer,_1384249-1),must_be/2) 139 | 140 | %?- m_factorial(1, F). 141 | %@ F = 1 142 | %@ ; false. 143 | 144 | %?- m_factorial(10, F). 145 | %@ F = 3628800 146 | %@ ; false. 147 | 148 | %?- m_factorial(N, 6). 149 | %@ N = 3 150 | %@ ; false. 151 | 152 | %% Do I dare ...? 153 | %?- m_factorial(N, 3628800). 154 | %@ N = 10 155 | %@ ; false. 156 | 157 | %?- m_factorial(N, 3628801). 158 | %@ false. 159 | 160 | %% CONCLUSION: Yes, monotonicity does ruin the 'magic' of Prolog. 161 | %% COROLLARY: _BUT_ 'magic' might not be such a great thing! 162 | -------------------------------------------------------------------------------- /exec/prolog/inconceivable.pl: -------------------------------------------------------------------------------- 1 | :- module(inconceivable, [ 2 | inconceivable/3 3 | ]). 4 | 5 | :- use_module(library(clpz)). 6 | :- use_module(library(format)). 7 | :- use_module(library(time)). 8 | :- use_module(library(charsio)). 9 | 10 | %% TODO: Refine the console output from inconceivable/3, with an understanding 11 | %% that it will generally be called on a Query that MUST FAIL. 12 | %% There may even be scope for omitting the separate Var argument 13 | %% by abstracting it automatically from the Query itself, recognized 14 | %% perhaps as the only unbound named variable. 15 | :- meta_predicate inconceivable(0, -, +). 16 | inconceivable(Query, Var, Range) :- 17 | %% TODO: Is there a way to get the name of Var as originally provided, 18 | %% instead of the renamed version? 19 | write_term_to_chars(Var, [], IndexName), % at present, IndexName invariably "A" 20 | Var in Range, 21 | indomain(Var), 22 | format(" % ~s = ~d ...", [IndexName, Var]), 23 | time(call(Query)). 24 | -------------------------------------------------------------------------------- /exec/prolog/subsumption.pl: -------------------------------------------------------------------------------- 1 | %% Explore universality of CCD 2 | :- use_module(library(clpz)). 3 | :- use_module(library(lambda)). 4 | :- use_module(library(format)). 5 | 6 | :- use_module(ccd). 7 | 8 | /* 9 | 10 | Initially, let's examine the apparently obvious connection between 11 | the traditional 3+3 design and CCD. If I am not wrong, a CCD with 12 | cohort size 3, cohort limit 6, and the following boundaries yields 13 | our usual 3+3: 14 | 15 | cumulative patients treated at current dose (n_j): 16 | 1 2 3 4 5 6 17 | 18 | lambda_{1,j} - - 0/3 0/4 0/5 1/6 19 | 20 | lambda_{2,j} - 2/2 2/3 2/4 2/5 2/6 21 | 22 | elimination - 2/2 2/3 2/4 2/5 2/6 23 | 24 | 25 | Note that the elimination and de-escalation boundaries are identical! 26 | 27 | */ 28 | 29 | traditional33(ccd([2/6], [2/6], [0/3, 1/6], 3, 6, 9999)). % 9999 ≈ sup 30 | 31 | traditional_d_matrix(D, Matrix) :- 32 | traditional33(T33), 33 | ccd_d_matrix(T33, D, Matrix). 34 | 35 | %?- traditional33(T33). 36 | %@ T33 = ccd([2/6],[2/6],[0/3,1/6],3,6,9999). 37 | 38 | %?- Matrix+\(traditional_d_matrix(2, Matrix)). 39 | %@ Matrix = ([0/3]^[0/6]^[]~>2) 40 | %@ ; Matrix = ([0/3]^[1/6]^[]~>2) 41 | %@ ; Matrix = ([]^[0/6]^[2/6]~>1) 42 | %@ ; Matrix = ([]^[1/6]^[2/6]~>1) 43 | %@ ; Matrix = ([]^[2/6]^[2/6]~>0) 44 | %@ ; Matrix = ([]^[3/6]^[2/6]~>0) 45 | %@ ; Matrix = ([]^[0/6]^[3/6]~>1) 46 | %@ ; Matrix = ([]^[1/6]^[3/6]~>1) 47 | %@ ; Matrix = ([]^[2/6]^[3/6]~>0) 48 | %@ ; Matrix = ([]^[3/6]^[3/6]~>0) 49 | %@ ; Matrix = ([0/3]^[1/6]^[]~>2) 50 | %@ ; Matrix = ([]^[0/6]^[2/6]~>1) 51 | %@ ; Matrix = ([]^[1/6]^[2/6]~>1) 52 | %@ ; Matrix = ([]^[2/6]^[2/6]~>0) 53 | %@ ; Matrix = ([]^[3/6]^[2/6]~>0) 54 | %@ ; Matrix = ([]^[0/6]^[3/6]~>1) 55 | %@ ; Matrix = ([]^[1/6]^[3/6]~>1) 56 | %@ ; Matrix = ([]^[2/6]^[3/6]~>0) 57 | %@ ; Matrix = ([]^[3/6]^[3/6]~>0) 58 | %@ ; Matrix = ([]^[0/6]^[4/6]~>1) 59 | %@ ; Matrix = ([]^[1/6]^[4/6]~>1) 60 | %@ ; Matrix = ([]^[2/6]^[4/6]~>0) 61 | %@ ; Matrix = ([]^[3/6]^[4/6]~>0) 62 | %@ ; Matrix = ([]^[0/6]^[2/3]~>1) 63 | %@ ; Matrix = ([]^[1/6]^[2/3]~>1) 64 | %@ ; Matrix = ([]^[2/6]^[2/3]~>0) 65 | %@ ; Matrix = ([]^[3/6]^[2/3]~>0) 66 | %@ ; Matrix = ([]^[0/6]^[3/3]~>1) 67 | %@ ; Matrix = ([]^[1/6]^[3/3]~>1) 68 | %@ ; Matrix = ([]^[2/6]^[3/3]~>0) 69 | %@ ; Matrix = ([]^[3/6]^[3/3]~>0) 70 | %@ ; Matrix = ([1/6]^[0/6]^[]~>2) 71 | %@ ; Matrix = ([1/6]^[1/6]^[]~>2) 72 | %@ ; Matrix = ([1/6]^[2/6]^[]~>1) 73 | %@ ; Matrix = ([1/6]^[3/6]^[]~>1) 74 | %@ ; Matrix = ([1/6]^[1/6]^[]~>2) 75 | %@ ; Matrix = ([1/6]^[2/6]^[]~>1) 76 | %@ ; Matrix = ([1/6]^[3/6]^[]~>1) 77 | %@ ; Matrix = ([1/6]^[4/6]^[]~>1) 78 | %@ ; Matrix = ([1/6]^[2/3]^[]~>1) 79 | %@ ; Matrix = ([1/6]^[3/3]^[]~>1) 80 | %@ ; Matrix = ([]^[2/6,0/0]^[]~>0) 81 | %@ ; Matrix = ([]^[3/6,0/0]^[]~>0) 82 | %@ ; Matrix = ([]^[4/6,0/0]^[]~>0) 83 | %@ ; Matrix = ([]^[2/3,0/0]^[]~>0) 84 | %@ ; Matrix = ([]^[3/3,0/0]^[]~>0) 85 | %@ ; false. 86 | 87 | %?- J+\(traditional33(T33), D=1, time(findall(M, ccd_d_matrix(T33, D, M), Ms)), length(Ms, J)). 88 | %@ % CPU time: 0.468 seconds 89 | %@ % CPU time: 0.472 seconds 90 | %@ J = 10. 91 | 92 | %?- J+\(traditional33(T33), D=2, time(findall(M, ccd_d_matrix(T33, D, M), Ms)), length(Ms, J)). 93 | %@ % CPU time: 2.779 seconds 94 | %@ % CPU time: 2.783 seconds 95 | %@ J = 46. 96 | 97 | %?- J+\(traditional33(T33), D=3, time(findall(M, ccd_d_matrix(T33, D, M), Ms)), length(Ms, J)). 98 | %@ % CPU time: 10.030 seconds 99 | %@ % CPU time: 10.034 seconds 100 | %@ J = 154. 101 | 102 | %?- J+\(traditional33(T33), D=4, time(findall(M, ccd_d_matrix(T33, D, M), Ms)), length(Ms, J)). 103 | %@ % CPU time: 32.094 seconds 104 | %@ % CPU time: 32.099 seconds 105 | %@ J = 442. 106 | 107 | %?- J+\(traditional33(T33), D=5, time(findall(M, ccd_d_matrix(T33, D, M), Ms)), length(Ms, J)). 108 | %@ % CPU time: 90.907 seconds 109 | %@ % CPU time: 90.911 seconds 110 | %@ J = 1162. 111 | 112 | %?- J+\(traditional33(T33), D=6, time(findall(M, ccd_d_matrix(T33, D, M), Ms)), length(Ms, J)). 113 | %@ % CPU time: 243.609 seconds 114 | %@ % CPU time: 243.613 seconds 115 | %@ J = 2890. 116 | 117 | %?- J+\(traditional33(T33), D=7, time(findall(M, ccd_d_matrix(T33, D, M), Ms)), length(Ms, J)). 118 | %@ % CPU time: 650.724 seconds 119 | %@ % CPU time: 650.728 seconds 120 | %@ J = 6922. 121 | -------------------------------------------------------------------------------- /exec/prolog/swi.pl: -------------------------------------------------------------------------------- 1 | :- use_module(library(clpfd)). 2 | 3 | % Approximate format_//2 as provided by Scryer's library(format): 4 | format_(Fs, Args) --> call(format__(Fs, Args)). 5 | 6 | format__(Fs, Args, Ls0, Ls) :- 7 | format(chars(Ls0,Ls), Fs, Args). 8 | 9 | -------------------------------------------------------------------------------- /exec/prolog/testD2: -------------------------------------------------------------------------------- 1 | [ 2 | ([0/1]^[0/6]^[]~>2),([0/1]^[1/6]^[]~>2),([0/1]^[1/6]^[]~>2),([0/1]^[2/6]^[]~>2), 3 | ([0/1]^[1/6]^[]~>2),([0/1]^[2/6]^[]~>2),([0/1]^[2/6]^[]~>2),([]^[0/2,3/6]^[]~>1), 4 | ([]^[1/6,3/6]^[]~>1),([]^[2/6,3/6]^[]~>1),([]^[2/6,3/6]^[]~>1),([]^[3/6,3/6]^[]~>0), 5 | ([]^[2/4,3/6]^[]~>0),([]^[2/3,3/6]^[]~>0),([0/1]^[1/6]^[]~>2),([0/1]^[2/6]^[]~>2), 6 | ([0/1]^[2/6]^[]~>2),([]^[0/2,3/6]^[]~>1),([]^[1/6,3/6]^[]~>1),([]^[2/6,3/6]^[]~>1), 7 | ([]^[2/6,3/6]^[]~>1),([]^[3/6,3/6]^[]~>0),([]^[2/4,3/6]^[]~>0),([]^[2/3,3/6]^[]~>0), 8 | ([0/2]^[2/6]^[]~>2),([]^[0/3,3/6]^[]~>1),([]^[1/6,3/6]^[]~>1),([]^[2/6,3/6]^[]~>1), 9 | ([]^[2/6,3/6]^[]~>1),([]^[3/6,3/6]^[]~>0),([]^[2/4,3/6]^[]~>0),([]^[0/6]^[3/5]~>1), 10 | ([]^[1/6]^[3/5]~>1),([]^[1/6]^[3/5]~>1),([]^[2/6]^[3/5]~>1),([]^[1/6]^[3/5]~>1), 11 | ([]^[2/6]^[3/5]~>1),([]^[2/6]^[3/5]~>1),([]^[3/6]^[3/5]~>0),([]^[1/6]^[3/5]~>1), 12 | ([]^[2/6]^[3/5]~>1),([]^[2/6]^[3/5]~>1),([]^[3/6]^[3/5]~>0),([]^[2/4]^[3/5]~>0), 13 | ([]^[1/6,2/4]^[]~>1),([]^[2/6,2/4]^[]~>1),([]^[2/6,2/4]^[]~>1),([]^[3/6,2/4]^[]~>0), 14 | ([]^[2/4,2/4]^[]~>0),([]^[2/3,2/4]^[]~>0),([0/1]^[1/6]^[]~>2),([0/1]^[2/6]^[]~>2), 15 | ([0/1]^[2/6]^[]~>2),([]^[0/2,3/6]^[]~>1),([]^[1/6,3/6]^[]~>1),([]^[2/6,3/6]^[]~>1), 16 | ([]^[2/6,3/6]^[]~>1),([]^[3/6,3/6]^[]~>0),([]^[2/4,3/6]^[]~>0),([]^[2/3,3/6]^[]~>0), 17 | ([0/2]^[2/6]^[]~>2),([]^[0/3,3/6]^[]~>1),([]^[1/6,3/6]^[]~>1),([]^[2/6,3/6]^[]~>1), 18 | ([]^[2/6,3/6]^[]~>1),([]^[3/6,3/6]^[]~>0),([]^[2/4,3/6]^[]~>0),([]^[0/6]^[3/5]~>1), 19 | ([]^[1/6]^[3/5]~>1),([]^[1/6]^[3/5]~>1),([]^[2/6]^[3/5]~>1),([]^[1/6]^[3/5]~>1), 20 | ([]^[2/6]^[3/5]~>1),([]^[2/6]^[3/5]~>1),([]^[3/6]^[3/5]~>0),([]^[1/6]^[3/5]~>1), 21 | ([]^[2/6]^[3/5]~>1),([]^[2/6]^[3/5]~>1),([]^[3/6]^[3/5]~>0),([]^[2/4]^[3/5]~>0), 22 | ([]^[1/6,2/4]^[]~>1),([]^[2/6,2/4]^[]~>1),([]^[2/6,2/4]^[]~>1),([]^[3/6,2/4]^[]~>0), 23 | ([]^[2/4,2/4]^[]~>0),([]^[2/3,2/4]^[]~>0),([0/3]^[2/6]^[]~>2),([]^[0/4,3/6]^[]~>1), 24 | ([]^[1/6,3/6]^[]~>1),([]^[2/6,3/6]^[]~>1),([]^[2/6,3/6]^[]~>1),([]^[3/6,3/6]^[]~>0), 25 | ([]^[0/6]^[3/5]~>1),([]^[1/6]^[3/5]~>1),([]^[1/6]^[3/5]~>1),([]^[2/6]^[3/5]~>1), 26 | ([]^[1/6]^[3/5]~>1),([]^[2/6]^[3/5]~>1),([]^[2/6]^[3/5]~>1),([]^[3/6]^[3/5]~>0), 27 | ([]^[1/6,2/4]^[]~>1),([]^[2/6,2/4]^[]~>1),([]^[2/6,2/4]^[]~>1),([]^[3/6,2/4]^[]~>0), 28 | ([]^[2/4,2/4]^[]~>0),([]^[0/6]^[3/4]~>1),([]^[1/6]^[3/4]~>1),([]^[1/6]^[3/4]~>1), 29 | ([]^[2/6]^[3/4]~>1),([]^[1/6]^[3/4]~>1),([]^[2/6]^[3/4]~>1),([]^[2/6]^[3/4]~>1), 30 | ([]^[3/6]^[3/4]~>0),([]^[1/6]^[3/4]~>1),([]^[2/6]^[3/4]~>1),([]^[2/6]^[3/4]~>1), 31 | ([]^[3/6]^[3/4]~>0),([]^[2/4]^[3/4]~>0),([]^[1/6,2/3]^[]~>1),([]^[2/6,2/3]^[]~>1), 32 | ([]^[2/6,2/3]^[]~>1),([]^[3/6,2/3]^[]~>0),([]^[2/4,2/3]^[]~>0),([]^[2/3,2/3]^[]~>0), 33 | ([0/2]^[1/6]^[]~>2),([0/2]^[2/6]^[]~>2),([0/2]^[2/6]^[]~>2),([]^[0/3,3/6]^[]~>1), 34 | ([]^[1/6,3/6]^[]~>1),([]^[2/6,3/6]^[]~>1),([]^[2/6,3/6]^[]~>1),([]^[3/6,3/6]^[]~>0), 35 | ([]^[2/4,3/6]^[]~>0),([0/3]^[2/6]^[]~>2),([]^[0/4,3/6]^[]~>1),([]^[1/6,3/6]^[]~>1), 36 | ([]^[2/6,3/6]^[]~>1),([]^[2/6,3/6]^[]~>1),([]^[3/6,3/6]^[]~>0),([]^[0/6]^[3/5]~>1), 37 | ([]^[1/6]^[3/5]~>1),([]^[1/6]^[3/5]~>1),([]^[2/6]^[3/5]~>1),([]^[1/6]^[3/5]~>1), 38 | ([]^[2/6]^[3/5]~>1),([]^[2/6]^[3/5]~>1),([]^[3/6]^[3/5]~>0),([]^[1/6,2/4]^[]~>1), 39 | ([]^[2/6,2/4]^[]~>1),([]^[2/6,2/4]^[]~>1),([]^[3/6,2/4]^[]~>0),([]^[2/4,2/4]^[]~>0), 40 | ([0/4]^[2/6]^[]~>2),([]^[0/5,3/6]^[]~>1),([]^[1/6,3/6]^[]~>1),([]^[2/6,3/6]^[]~>1), 41 | ([]^[0/6]^[3/5]~>1),([]^[1/6]^[3/5]~>1),([]^[1/6]^[3/5]~>1),([]^[2/6]^[3/5]~>1), 42 | ([]^[1/6,2/4]^[]~>1),([]^[2/6,2/4]^[]~>1),([]^[2/6,2/4]^[]~>1),([]^[3/6,2/4]^[]~>0), 43 | ([]^[0/6]^[3/4]~>1),([]^[1/6]^[3/4]~>1),([]^[1/6]^[3/4]~>1),([]^[2/6]^[3/4]~>1), 44 | ([]^[1/6]^[3/4]~>1),([]^[2/6]^[3/4]~>1),([]^[2/6]^[3/4]~>1),([]^[3/6]^[3/4]~>0), 45 | ([]^[1/6,2/3]^[]~>1),([]^[2/6,2/3]^[]~>1),([]^[2/6,2/3]^[]~>1),([]^[3/6,2/3]^[]~>0), 46 | ([]^[2/4,2/3]^[]~>0),([0/5]^[2/6]^[]~>2),([]^[0/6,3/6]^[]~>1),([]^[1/6,3/6]^[]~>1), 47 | ([]^[0/6]^[3/5]~>1),([]^[1/6]^[3/5]~>1),([]^[1/6,2/4]^[]~>1),([]^[2/6,2/4]^[]~>1), 48 | ([]^[0/6]^[3/4]~>1),([]^[1/6]^[3/4]~>1),([]^[1/6]^[3/4]~>1),([]^[2/6]^[3/4]~>1), 49 | ([]^[1/6,2/3]^[]~>1),([]^[2/6,2/3]^[]~>1),([]^[2/6,2/3]^[]~>1),([]^[3/6,2/3]^[]~>0), 50 | ([]^[0/6]^[3/3]~>1),([]^[1/6]^[3/3]~>1),([]^[1/6]^[3/3]~>1),([]^[2/6]^[3/3]~>1), 51 | ([]^[1/6]^[3/3]~>1),([]^[2/6]^[3/3]~>1),([]^[2/6]^[3/3]~>1),([]^[3/6]^[3/3]~>0), 52 | ([]^[1/6,2/2]^[]~>1),([]^[2/6,2/2]^[]~>1),([]^[2/6,2/2]^[]~>1),([]^[3/6,2/2]^[]~>0), 53 | ([]^[2/4,2/2]^[]~>0),([]^[1/6,1/1]^[]~>1),([]^[2/6,1/1]^[]~>1),([]^[2/6,1/1]^[]~>1), 54 | ([]^[3/6,1/1]^[]~>0),([]^[2/4,1/1]^[]~>0),([]^[2/3,1/1]^[]~>0),([]^[1/1,0/0]^[]~>0) 55 | ]. 56 | -------------------------------------------------------------------------------- /exec/scryer.pl: -------------------------------------------------------------------------------- 1 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2 | Setup file to run esc.pl with Scryer Prolog. 3 | 4 | Scryer Prolog is a modern Prolog system implemented in Rust, 5 | a language that provides desirable safety guarantees and performance. 6 | 7 | Scryer Prolog aims for compliance with the Prolog ISO standard. 8 | It is available from https://github.com/mthom/scryer-prolog/ 9 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 10 | 11 | :- use_module(library(format)). 12 | :- use_module(library(lists)). 13 | :- use_module(library(dcgs)). 14 | :- use_module(library(clpz)). 15 | :- use_module(library(time)). 16 | 17 | nth1(N, List, Elt) :- nth0(N, [elt0|List], Elt). 18 | -------------------------------------------------------------------------------- /exec/sicstus.pl: -------------------------------------------------------------------------------- 1 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2 | Setup file to run esc.pl with SICStus Prolog. 3 | 4 | SICStus Prolog is a state-of-the-art, ISO standard compliant 5 | Prolog development system, available from: https://sicstus.sics.se/ 6 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 7 | 8 | :- use_module(library(clpfd)). 9 | :- use_module(library(lists)). 10 | 11 | % Approximate format_//2 as provided by Scryer's library(format): 12 | :- use_module(library(codesio)). 13 | 14 | format_(Fs, Args) --> call(format__(Fs, Args)). 15 | 16 | format__(Fs, Args, Ls0, Ls) :- 17 | with_output_to_codes(format(Fs, Args), Codes, []), 18 | atom_codes(Atom, Codes), 19 | atom_chars(Atom, Chars), 20 | append(Chars, Ls, Ls0). 21 | -------------------------------------------------------------------------------- /inst/WORDLIST: -------------------------------------------------------------------------------- 1 | st 2 | nd 3 | th 4 | abovementioned 5 | arg 6 | au contraire 7 | AFM 8 | arXiv 9 | basedness 10 | Bayesianism 11 | bioRxiv 12 | biostatistical 13 | biostatisticians 14 | Boin 15 | BOIN 16 | BOIN's 17 | boldsymbol 18 | Braun 19 | Braun's 20 | cacheing 21 | CCD 22 | CCDs 23 | Chappell 24 | Chen TT 25 | Cheung 26 | Cheung's 27 | cloneable 28 | CMD 29 | cohortwise 30 | CPE 31 | CRM 32 | CRM's 33 | CTCAE 34 | designator 35 | DLT 36 | doi 37 | DOI 38 | dose recs 39 | DTAT 40 | enumerative 41 | EscRisk 42 | eq 43 | Eq 44 | et al 45 | exchangeably 46 | FDA 47 | FDA's 48 | Flournoy 49 | frac 50 | fractionation 51 | generalizability 52 | Gustafson 53 | https 54 | hyperprior 55 | integrand 56 | intercal 57 | interpretational 58 | investigational 59 | isotonic 60 | iteratively 61 | Ivanova 62 | JAMA 63 | Korn 64 | Korn EL 65 | Lifecycle 66 | Liu 67 | lognormally 68 | mathbf 69 | mathrm 70 | mathscr 71 | mbox 72 | MCSE 73 | memoization 74 | methodologic 75 | methodologists 76 | Midthune 77 | misspecification 78 | MTD 79 | MTDi 80 | MTDig 81 | mTPI 82 | multiplier 83 | Nelder 84 | newpage 85 | ng 86 | OCE 87 | ordinalization 88 | ordinalizer 89 | parametrizing 90 | per se 91 | pharmacodynamics 92 | pharmacokinetics 93 | pharmacologic 94 | pharmacologically 95 | prebuilt 96 | preclinical 97 | precomputed 98 | prespecify 99 | pretabulated 100 | programmatically 101 | programme 102 | Prolog 103 | Prolog's 104 | pst 105 | QRNG 106 | rebranded 107 | Rubinstein LV 108 | runnable 109 | safetytab 110 | Scryer 111 | subclasses 112 | TITE 113 | titration 114 | tolerability 115 | tox 116 | trialist 117 | trialist's 118 | VIOLA 119 | VIOLA's 120 | wikipedia 121 | -------------------------------------------------------------------------------- /inst/shiny-apps/EscRisk/www/events.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | 3 | var editing_skeleton = 0; 4 | 5 | const skel_probs = document.getElementById('crm-skeleton'); 6 | skel_probs.addEventListener('focusout', e => { 7 | editing_skeleton = editing_skeleton - 1; 8 | setTimeout(function() { 9 | if (!editing_skeleton) { 10 | Shiny.setInputValue("editing_skeleton", false); 11 | } 12 | }); // TODO: Any need to set non-zero delay? 13 | }); 14 | skel_probs.addEventListener('focusin', e => { 15 | Shiny.setInputValue("editing_skeleton", true); 16 | editing_skeleton = editing_skeleton + 1; 17 | }); 18 | 19 | const outputJ = document.getElementById('J'); 20 | Shiny.addCustomMessageHandler('watch-J', function(J) { 21 | outputJ.innerHTML = J; 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /inst/shiny-apps/EscRisk/www/help.js: -------------------------------------------------------------------------------- 1 | // initialize an introjs instance 2 | var intro = introJs(); 3 | 4 | /* 5 | * Hard-coding the help system as below avoids complexities of R -> Javascript 6 | * communication, as well as awkwardness of typing in a data.frame representation. 7 | * In theory, however, we do lose the ability to customize help text on-the-fly, 8 | * which might be useful for commenting on particular outputs in the safety table. 9 | */ 10 | intro.setOptions({steps: [ 11 | { 12 | element: '#dose-levels', 13 | intro: "This app assumes your dose-escalation study uses a fixed set of 3–7 doses. You can span the range between lowest and highest doses using an arithmetic or geometric sequence, or manually customize the doses.", 14 | position: 'bottom' 15 | }, 16 | { 17 | element: '#optimal-dose-heterogeneity', 18 | intro: "A crucial perspective adopted by this app is that the optimal dose of the drug will vary from patient to patient. This app models this variability as a log-normally distributed ‘MTDi’. You are asked to provide ...", 19 | position: 'top' 20 | }, 21 | { 22 | element: document.querySelector('#median_mtd').parentElement, 23 | intro: "your best guess about the median MTDi in the population, i.e. the dose that will cause a dose-limiting toxicity (DLT) in half of the patient population; ...", 24 | position: 'bottom' 25 | }, 26 | { 27 | element: document.querySelector('#sigma_median').parentElement, 28 | intro: "an indication of your uncertainty about that median, expressed as a percentage ± ...", 29 | position: 'bottom' 30 | }, 31 | { 32 | element: document.querySelector('#sigma_CV').parentElement, 33 | intro: "and your guess as to the coefficient of variation (CV) of MTDi within the population.", 34 | // "
    For reasons outlined in the introductory vignette for R package 'precautionary', you don't need to further specify your uncertainty about σCV.", 35 | position: 'bottom' 36 | }, 37 | { 38 | element: '#hyperprior', 39 | intro: "You see here 1000 possible MTDi distributions, drawn randomly from the hyperprior you define via median MTDi, σmedian and σCV. To gain a better sense for the meaning of these parameters, experiment with different values while observing how this plot shifts and stretches.", 40 | position: 'bottom' 41 | }, 42 | { 43 | element: '#resample', 44 | intro: "You can also click this button to resample the hyperprior, and check the stability of the results.", 45 | position: 'right' 46 | }, 47 | { 48 | element: '#dose-escalation-design', 49 | intro: "You can choose from several popular dose-finding designs, and input values for applicable design parameters.", 50 | position: 'right' 51 | }, 52 | { 53 | element: '#crm-skeleton', 54 | intro: "If you choose the CRM, you can enter its skeleton here, or accept defaults obtained from the hyperprior sample", 55 | position: 'right' 56 | }, 57 | { 58 | element: document.querySelector('#r0').parentElement, 59 | intro: "Even when your dose-finding design recognizes only binary DLT's, you can still anticipate graded toxicities provided you are willing to venture a guess as to your drug's therapeutic index (TI). In a dose-finding trial conducted under an ‘MTD heuristic’, the most useful TI notion is a dosing ratio r0 that relates adjacent high-level toxicities. Ask yourself, Typically, what dose multiplier would push a grade-3 toxicity up to grade 4, or a grade-4 toxicity up to grade 5? (Example: If you expect that a 50% increase in dose would typically bump the toxicity grade up by 1 level, then set r0 = 1.5.)", 60 | position: 'top' 61 | }, 62 | { 63 | element: '#safety', 64 | intro: "This simple table contains the key safety-related quantities of interest, as estimated from your trial simulations together with r0. Expected total enrollment is broken down into expected numbers of patients who will experience each grade of toxicity. Obviously, the numbers of patients expected to experience grade-4 and grade-5 toxicities are of primary concern from a safety standpoint.", 65 | position: 'top' 66 | } 67 | ]}); 68 | 69 | // TODO: Understand why this doesn't get invoked properly from server 70 | // handler 1 71 | Shiny.addCustomMessageHandler("setHelpContent", 72 | 73 | // callback function. 74 | // note: data is passed by shiny and contains the tour data 75 | function(data){ 76 | 77 | // load data 78 | intro.setOptions({steps: data}); 79 | } 80 | ); 81 | 82 | // handler 2 83 | Shiny.addCustomMessageHandler("startHelp", function(message) { 84 | 85 | // start intro.js 86 | // note: we don't need information from shiny, just start introJS 87 | intro.start(); 88 | } 89 | ); 90 | -------------------------------------------------------------------------------- /inst/shiny-apps/EscRisk/www/tweaks.css: -------------------------------------------------------------------------------- 1 | .shiny-split-layout { 2 | padding-left: 4px; 3 | padding-right: 4px; 4 | } 5 | 6 | .shiny-split-layout div { 7 | margin-left: 0; 8 | margin-right: -4px; 9 | padding-right: 2px; 10 | padding-left: 2px; 11 | } 12 | 13 | .shiny-options-group { 14 | margin: 8px; 15 | } 16 | 17 | fieldset { 18 | font-family: sans-serif; 19 | border: 1px solid #ccc; 20 | border-radius: 3px; 21 | padding: 0; 22 | } 23 | 24 | fieldset legend { 25 | display: block; 26 | color: #aaa; /* text color */ 27 | font-size: 12px; 28 | font-weight: bold; 29 | font-variant: small-caps; 30 | border: none; 31 | text-align: center; 32 | padding: 4px; 33 | width: auto; 34 | margin-bottom: 0; 35 | } 36 | -------------------------------------------------------------------------------- /man/Boin-class.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/boin.R 3 | \name{Boin-class} 4 | \alias{Boin-class} 5 | \alias{Boin} 6 | \title{The BOIN design as a Cumulative-Cohort Design (CCD) subclass} 7 | \description{ 8 | The BOIN design as a Cumulative-Cohort Design (CCD) subclass 9 | 10 | The BOIN design as a Cumulative-Cohort Design (CCD) subclass 11 | } 12 | \details{ 13 | TODO: Provide references, and note clearly the choice of defaults. 14 | Also provide citations to BOIN paper(s). 15 | } 16 | \examples{ 17 | 18 | ## ------------------------------------------------ 19 | ## Method `Boin$new` 20 | ## ------------------------------------------------ 21 | 22 | # TODO 23 | } 24 | \section{Super classes}{ 25 | \code{\link[precautionary:Cpe]{precautionary::Cpe}} -> \code{\link[precautionary:Ccd]{precautionary::Ccd}} -> \code{Boin} 26 | } 27 | \section{Methods}{ 28 | \subsection{Public methods}{ 29 | \itemize{ 30 | \item \href{#method-new}{\code{Boin$new()}} 31 | \item \href{#method-clone}{\code{Boin$clone()}} 32 | } 33 | } 34 | \if{html}{ 35 | \out{
    Inherited methods} 36 | \itemize{ 37 | \item \out{}\href{../../precautionary/html/Cpe.html#method-J}{\code{precautionary::Cpe$J()}}\out{} 38 | \item \out{}\href{../../precautionary/html/Cpe.html#method-bU}{\code{precautionary::Cpe$bU()}}\out{} 39 | \item \out{}\href{../../precautionary/html/Cpe.html#method-decision_array}{\code{precautionary::Cpe$decision_array()}}\out{} 40 | \item \out{}\href{../../precautionary/html/Cpe.html#method-max_dose}{\code{precautionary::Cpe$max_dose()}}\out{} 41 | \item \out{}\href{../../precautionary/html/Cpe.html#method-path_array}{\code{precautionary::Cpe$path_array()}}\out{} 42 | \item \out{}\href{../../precautionary/html/Cpe.html#method-path_matrix}{\code{precautionary::Cpe$path_matrix()}}\out{} 43 | \item \out{}\href{../../precautionary/html/Cpe.html#method-path_probs}{\code{precautionary::Cpe$path_probs()}}\out{} 44 | \item \out{}\href{../../precautionary/html/Cpe.html#method-path_rx}{\code{precautionary::Cpe$path_rx()}}\out{} 45 | \item \out{}\href{../../precautionary/html/Cpe.html#method-report}{\code{precautionary::Cpe$report()}}\out{} 46 | \item \out{}\href{../../precautionary/html/Cpe.html#method-trace_paths}{\code{precautionary::Cpe$trace_paths()}}\out{} 47 | \item \out{}\href{../../precautionary/html/Ccd.html#method-applied}{\code{precautionary::Ccd$applied()}}\out{} 48 | } 49 | \out{
    } 50 | } 51 | \if{html}{\out{
    }} 52 | \if{html}{\out{}} 53 | \if{latex}{\out{\hypertarget{method-new}{}}} 54 | \subsection{Method \code{new()}}{ 55 | \subsection{Usage}{ 56 | \if{html}{\out{
    }}\preformatted{Boin$new(target, cohort_max, enroll_max)}\if{html}{\out{
    }} 57 | } 58 | 59 | \subsection{Arguments}{ 60 | \if{html}{\out{
    }} 61 | \describe{ 62 | \item{\code{target}}{Target toxicity rate} 63 | 64 | \item{\code{cohort_max}}{Upper bound on dose-wise enrollment} 65 | 66 | \item{\code{enroll_max}}{Upper bound on total enrollment} 67 | } 68 | \if{html}{\out{
    }} 69 | } 70 | \subsection{Details}{ 71 | Create a new \code{Boin} object. 72 | } 73 | 74 | \subsection{Returns}{ 75 | A Boin object. 76 | } 77 | \subsection{Examples}{ 78 | \if{html}{\out{
    }} 79 | \preformatted{# TODO 80 | } 81 | \if{html}{\out{
    }} 82 | 83 | } 84 | 85 | } 86 | \if{html}{\out{
    }} 87 | \if{html}{\out{}} 88 | \if{latex}{\out{\hypertarget{method-clone}{}}} 89 | \subsection{Method \code{clone()}}{ 90 | The objects of this class are cloneable with this method. 91 | \subsection{Usage}{ 92 | \if{html}{\out{
    }}\preformatted{Boin$clone(deep = FALSE)}\if{html}{\out{
    }} 93 | } 94 | 95 | \subsection{Arguments}{ 96 | \if{html}{\out{
    }} 97 | \describe{ 98 | \item{\code{deep}}{Whether to make a deep clone.} 99 | } 100 | \if{html}{\out{
    }} 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /man/as.data.table.exact.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/exact.R 3 | \name{as.data.table.exact} 4 | \alias{as.data.table.exact} 5 | \title{Convert an object of class c('exact','precautionary','simulations') to a data.table} 6 | \usage{ 7 | \method{as.data.table}{exact}( 8 | x, 9 | keep.rownames = FALSE, 10 | ordinalizer = getOption("ordinalizer"), 11 | ... 12 | ) 13 | } 14 | \arguments{ 15 | \item{x}{An object of class c('precautionary','simulations')} 16 | 17 | \item{keep.rownames}{Unused; retained for S3 generic/method consistency} 18 | 19 | \item{ordinalizer}{If not NULL, this is a function mapping the threshold 20 | dose ('MTDi') at which an individual experiences a binary toxicity (as 21 | recognized by the dose-escalation design) to a named vector giving dose 22 | thresholds for multiple grades of toxicity. The names of this vector will 23 | be taken as designations of the toxicity grades.} 24 | 25 | \item{...}{Additional parameters passed to the \code{ordinalizer}} 26 | } 27 | \description{ 28 | TODO: Actually implement this! 29 | } 30 | -------------------------------------------------------------------------------- /man/as.data.table.precautionary.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/enhance.R 3 | \name{as.data.table.precautionary} 4 | \alias{as.data.table.precautionary} 5 | \title{Convert an object of class c('precautionary','simulations') to a data.table} 6 | \usage{ 7 | \method{as.data.table}{precautionary}( 8 | x, 9 | keep.rownames = FALSE, 10 | ordinalizer = getOption("ordinalizer"), 11 | ... 12 | ) 13 | } 14 | \arguments{ 15 | \item{x}{An object of class c('precautionary','simulations')} 16 | 17 | \item{keep.rownames}{Unused; retained for S3 generic/method consistency} 18 | 19 | \item{ordinalizer}{If not NULL, this is a function mapping the threshold 20 | dose ('MTDi') at which an individual experiences a binary toxicity (as 21 | recognized by the dose-escalation design) to a named vector giving dose 22 | thresholds for multiple grades of toxicity. The names of this vector will 23 | be taken as designations of the toxicity grades.} 24 | 25 | \item{...}{Additional parameters passed to the \code{ordinalizer}} 26 | } 27 | \description{ 28 | Convert an object of class c('precautionary','simulations') to a data.table 29 | } 30 | -------------------------------------------------------------------------------- /man/cohorts_of_n.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/enhance.R 3 | \name{cohorts_of_n} 4 | \alias{cohorts_of_n} 5 | \title{Override \code{\link[escalation]{cohorts_of_n}} to include latent toxicity tolerances} 6 | \usage{ 7 | cohorts_of_n(n = 3, mean_time_delta = 1) 8 | } 9 | \arguments{ 10 | \item{n}{integer, sample arrival times for this many patients.} 11 | 12 | \item{mean_time_delta}{the average gap between patient arrival times. I.e. 13 | the reciprocal of the rate parameter in an Exponential distribution.} 14 | } 15 | \value{ 16 | \code{data.frame} with columns \code{u_i} and \code{time_delta} 17 | containing respectively the uniformly-distributed latent toxicity tolerance 18 | and arrival-time increment for each trial participant. 19 | } 20 | \description{ 21 | The original function in package \CRANpkg{escalation} recognizes that individual 22 | trial participants arrive at distinct times. Building upon this acknowledgment 23 | of individuality, this override adds an extra line of code to draw as well a 24 | latent toxicity tolerance \code{u_i} for each individual participant. 25 | } 26 | \examples{ 27 | cohorts_of_n() 28 | cohorts_of_n(n = 10, mean_time_delta = 5) 29 | } 30 | \seealso{ 31 | \code{\link[=phase1_sim]{phase1_sim()}}, which this package also overrides with similarly 32 | minute changes in order to incorporate \code{u_i}. 33 | } 34 | -------------------------------------------------------------------------------- /man/crm.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/crm.R 3 | \name{crm} 4 | \alias{crm} 5 | \title{A package-local (as-yet, unexported) test harness adapted from \code{dfcrm::crm()}.} 6 | \usage{ 7 | crm( 8 | prior, 9 | target, 10 | tox, 11 | level, 12 | n = length(level), 13 | dosename = NULL, 14 | include = 1:n, 15 | pid = 1:n, 16 | conf.level = 0.9, 17 | method = "bayes", 18 | model = "empiric", 19 | intcpt = 3, 20 | scale = sqrt(1.34), 21 | model.detail = TRUE, 22 | patient.detail = TRUE, 23 | var.est = TRUE, 24 | impl = c("rusti", "ruste", "dfcrm") 25 | ) 26 | } 27 | \arguments{ 28 | \item{prior}{The CRM skeleton: dose-wise prior probabilities of toxicity} 29 | 30 | \item{target}{Target toxicity rate} 31 | 32 | \item{tox}{A patient-wise vector of toxicity counts} 33 | 34 | \item{level}{A patient-wise vector of dose level assignments} 35 | 36 | \item{n}{The number of patients enrolled} 37 | 38 | \item{dosename}{Optional designators for the doses} 39 | 40 | \item{include}{Index of patients to include} 41 | 42 | \item{pid}{Vector of patient ID labels} 43 | 44 | \item{conf.level}{Used to assign upper and lower bounds on predicted probability 45 | of toxicity, which in turn may be referenced in escalation, deescalation and 46 | stopping decisions.} 47 | 48 | \item{method}{Estimation method:} 49 | 50 | \item{model}{Presently, only the \sQuote{empiric} (or \sQuote{power}) model 51 | has a Rust likelihood implementation.} 52 | 53 | \item{intcpt}{Intercept for \sQuote{logistic} model} 54 | 55 | \item{scale}{Sigma parameter of prior on beta parameter} 56 | 57 | \item{model.detail}{If FALSE, the model content of an \code{mtd} object will not 58 | be displayed. Default is TRUE.} 59 | 60 | \item{patient.detail}{If FALSE, patient summary of an \code{mtd} object will not 61 | be displayed. Default is TRUE.} 62 | 63 | \item{var.est}{If TRUE, variance of the estimate of the model parameter and 64 | probability/confidence interval for the dose-toxicity curve will be computed} 65 | 66 | \item{impl}{Switch between \code{'rusti'} and \code{'dfcrm'} implementations. 67 | Currently the \code{'rusti'} option is implemented only for the Bayes method 68 | of the empirical (\sQuote{power}) model. An experimental \code{'ruste'} 69 | implementation is in the works.} 70 | } 71 | \description{ 72 | for various performance tuning experiments. The \code{impl} arg allows selection 73 | of various alternative implementations: 74 | \itemize{ 75 | \item \code{'rusti'} substitutes integrands \code{crmh}, \code{crmht}, \code{crmht2} written in Rust 76 | \item \code{'dfcrm'} is the original as implemented in package \code{dfcrm}. 77 | } 78 | } 79 | \author{ 80 | Adapted by David C. Norris, from Ken Cheung's \CRANpkg{dfcrm} 81 | } 82 | -------------------------------------------------------------------------------- /man/crmh.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/extendr-wrappers.R 3 | \name{crmh} 4 | \alias{crmh} 5 | \alias{crmht} 6 | \alias{crmht2} 7 | \title{Rust implementation of \verb{dfcrm::crmh*} integrands} 8 | \usage{ 9 | crmh(a, ln_x, w, s) 10 | 11 | crmht(a, ln_x, w, s) 12 | 13 | crmht2(a, ln_x, w, s) 14 | } 15 | \arguments{ 16 | \item{a}{Numeric vector of evaluation points} 17 | 18 | \item{ln_x}{A numeric vector of dose-wise prior log-probabilities of toxicity} 19 | 20 | \item{w}{Patient-wise weights (used for TITE CRM), also encoding toxicity 21 | by \code{w[i] == 0.0}.} 22 | 23 | \item{s}{Scalar scale factor} 24 | } 25 | \description{ 26 | Rust implementation of \verb{dfcrm::crmh*} integrands 27 | } 28 | \section{Functions}{ 29 | \itemize{ 30 | \item \code{crmh}: Posterior for 1-parameter empiric (aka 'power') model 31 | 32 | \item \code{crmht}: Integrand for 1st moment of empiric posterior 33 | 34 | \item \code{crmht2}: Integrand for 2nd moment of empiric posterior 35 | }} 36 | 37 | -------------------------------------------------------------------------------- /man/crmh_xo.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/extendr-wrappers.R 3 | \name{crmh_xo} 4 | \alias{crmh_xo} 5 | \title{Rust implementation of \verb{dfcrm::crmh*} integrands for w==1 case} 6 | \usage{ 7 | crmh_xo(a, ln_x, tox, nos, s, b) 8 | } 9 | \arguments{ 10 | \item{a}{Numeric vector of evaluation points} 11 | 12 | \item{ln_x}{A numeric vector of dose-wise prior log-probabilities of toxicity} 13 | 14 | \item{tox}{A numeric vector; a dose-wise tally of toxicities} 15 | 16 | \item{nos}{A numeric vector; a dose-wise tally of non-toxicities} 17 | 18 | \item{s}{Scalar scale factor} 19 | 20 | \item{b}{Order of moment to calculate (0, 1 or 2)} 21 | } 22 | \description{ 23 | Rust implementation of \verb{dfcrm::crmh*} integrands for w==1 case 24 | } 25 | -------------------------------------------------------------------------------- /man/exact.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/exact.R 3 | \name{exact} 4 | \alias{exact} 5 | \title{A wrapper function supporting exact simulation of dose-escalation trials.} 6 | \usage{ 7 | exact(selector_factory) 8 | } 9 | \arguments{ 10 | \item{selector_factory}{An object of type 11 | \code{\link[escalation:get_three_plus_three]{three_plus_three_selector_factory}}, 12 | with \code{allow_deescalation = TRUE}.} 13 | } 14 | \description{ 15 | Implemented currently only for the (most?) common variant of the 3+3 design, 16 | which requires that at least 6 patients be treated at a dose before it may be 17 | declared as \sQuote{the} MTD. 18 | } 19 | \details{ 20 | In any given realization of a 3+3 design, each of the \eqn{D} prespecified doses 21 | will enroll 0, 1 or 2 cohorts, each with 3 patients. Each cohort will result in 22 | a tally of 0--3 dose-limiting toxicities (DLTs), and these may be recorded in a 23 | \eqn{2 \times D}{2 x D} matrix. Moreover, the 3+3 dose-escalation rules allow for 24 | only one path through any such matrix. For example, the matrix 25 | \preformatted{ 26 | d 27 | c D1 D2 D3 D4 28 | 1 0 1 2 NA 29 | 2 NA 0 NA NA 30 | } 31 | represents the path in a 4-dose 3+3 trial, where the following events occur: 32 | \enumerate{ 33 | \item Initial cohort at \eqn{d=1} results 0/3 34 | \item Escalation to \eqn{d=2} results 1/3 35 | \item Additional cohort at \eqn{d=2} results 0/3 for net 1/6 at this dose 36 | \item Escalation to \eqn{d=3} results 2/3; MTD declared as \eqn{d=1}. 37 | } 38 | (Indeed, as you may verify at the R prompt, the above matrix is the 262nd of 442 39 | such paths enumerated comprehensively in the \eqn{2 \times 4 \times 442}{2 x 4 x 442} 40 | array \code{precautionary:::T[[4]]}.) 41 | 42 | As detailed in Norris 2020c (below), these matrices may be used to construct simple 43 | matrix computations that altogether eliminate the need for discrete-event simulation 44 | of the 3+3 design. For each \eqn{D = 2,...,8}, the \code{precautionary} package has 45 | pretabulated a \eqn{J \times 2D}{J x 2D} matrix \code{precautionary:::U[[D]]} and 46 | \eqn{J}-vector \code{precautionary:::b[[D]]} such that the \eqn{J}-vector \eqn{\pi} 47 | of path probabilities is given by: 48 | \deqn{ 49 | log(\pi) = b + U [log(p), log(q)]', 50 | } 51 | where \eqn{p} is the \eqn{D}-vector of DLT probabilities at the prespecified 52 | doses, and \eqn{q \equiv 1-p}{q := 1-p} is its complement. See Eq. (4) of 53 | Norris (2020c). 54 | 55 | For details on the enumeration itself, please see the Prolog code in directory 56 | \verb{exec/} of the installed package. 57 | } 58 | \examples{ 59 | # Run an exact version of the simulation from FDA-proactive vignette 60 | design <- get_three_plus_three( 61 | num_doses = 6 62 | , allow_deescalate = TRUE) 63 | old <- options( 64 | dose_levels = c(2, 6, 20, 60, 180, 400) 65 | , ordinalizer = function(MTDi, r0 = 1.5) 66 | MTDi * r0 ^ c(Gr1=-2, Gr2=-1, Gr3=0, Gr4=1, Gr5=2) 67 | ) 68 | mtdi_gen <- hyper_mtdi_lognormal(CV = 0.5 69 | ,median_mtd = 180 70 | ,median_sdlog = 0.6 71 | ,units="ng/kg/week") 72 | exact(design) \%>\% simulate_trials( 73 | num_sims = 1000 74 | , true_prob_tox = mtdi_gen) -> EXACT 75 | summary(EXACT)$safety 76 | if (interactive()) { # runs too long for CRAN servers 77 | # Compare with discrete-event-simulation trials 78 | design \%>\% simulate_trials( 79 | num_sims = 1000 80 | , true_prob_tox = mtdi_gen) -> DISCRETE 81 | summary(DISCRETE)$safety[,] 82 | # Note the larger MCSEs in this latter simulation, reflecting combined noise 83 | # from hyperprior sampling and the nested discrete-event trial simulations. 84 | # The MCSE of the former simulation is purely from the hyperprior sampling, 85 | # since the nested trial simulation is carried out by an exact computation. 86 | } 87 | options(old) 88 | } 89 | \references{ 90 | Norris DC. What Were They Thinking? Pharmacologic priors implicit in a choice 91 | of 3+3 dose-escalation design. arXiv:2012.05301 [stat.ME]. December 2020. 92 | \url{https://arxiv.org/abs/2012.05301} 93 | } 94 | -------------------------------------------------------------------------------- /man/extend.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/simulate_trials.R 3 | \name{extend} 4 | \alias{extend} 5 | \title{Extend an existing simulation, using one of several stopping criteria} 6 | \usage{ 7 | extend(sims, num_sims = NULL, target_mcse = 0.05) 8 | } 9 | \arguments{ 10 | \item{sims}{An existing object of class \code{c('precautionary','simulations')}} 11 | 12 | \item{num_sims}{Optionally, a fixed number of additional replications to accumulate} 13 | 14 | \item{target_mcse}{Optionally, an MCSE constraint to be imposed on expected counts 15 | of DLTs, non-DLTs, and Total enrollment.} 16 | } 17 | \value{ 18 | An extended simulation of same class as \code{sims}. 19 | } 20 | \description{ 21 | A trial simulation carried through a predetermined number of replications 22 | may not achieve desired precision as judged by Monte Carlo standard errors 23 | (MCSE) of estimated toxicity counts. This method enables simulations of 24 | class \code{c('precautionary','simulations')} to be extended until a given 25 | level of precision has been achieved on expected counts of enrollment and 26 | DLTs, or (optionally) for a fixed additional number of simulations. 27 | } 28 | \note{ 29 | The MCSE constraint is imposed during trial \emph{simulation}, at which 30 | point only \emph{binary} toxicities are available. Thus, as a practical matter, 31 | \code{extend} can target MCSEs only for DLTs, non-DLTs and Total enrollment. 32 | The subsequent subdivision of these categories during trial \emph{summary} 33 | (at which point the ordinalizer comes into play along with its parameters) thus 34 | may generate expected counts with MCSEs exceeding \code{target_mcse}. 35 | In practice, however, this tends to affect the estimated counts only for the 36 | \emph{lowest} toxicity grades---those of least concern from a trial-safety 37 | perspective. 38 | } 39 | \seealso{ 40 | See examples under \link{simulate_trials} and \link{format.safetytab}. 41 | } 42 | -------------------------------------------------------------------------------- /man/figures/logo.svg: -------------------------------------------------------------------------------- 1 | image/svg+xmlCAUTIONPREARY -------------------------------------------------------------------------------- /man/format.safetytab.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/enhance.R 3 | \name{format.safetytab} 4 | \alias{format.safetytab} 5 | \title{Format a phase 1 trial safety tabulation to show significant digits only} 6 | \usage{ 7 | \method{format}{safetytab}(x, ...) 8 | } 9 | \arguments{ 10 | \item{x}{A safety tabulation as found in the \code{safety} component of the 11 | list returned by \link{summary.precautionary}.} 12 | 13 | \item{...}{Unused; included for compatibility with generic signature} 14 | } 15 | \description{ 16 | The essential insight of package \link{precautionary} is distilled into the 17 | \emph{safety tabulation} which it generates from trial simulations, reporting 18 | the expected number of patients who will experience each grade of toxicity. 19 | To render this table for easy interpretation, these expectations are simply 20 | displayed with a number of significant digits appropriate to their Monte Carlo 21 | standard errors (MCSEs). 22 | } 23 | \note{ 24 | The MCSEs of safety tabulations remain available for inspection 25 | (see example), but are omitted from standard displays because they may lend 26 | themselves to misinterpretation as \emph{confidence bounds} on the number 27 | of patients who will experience each toxicity grade \emph{in any given trial}. 28 | } 29 | \examples{ 30 | mtdi_gen <- hyper_mtdi_lognormal(CV = 1 31 | ,median_mtd = 5 32 | ,median_sdlog = 0.5 33 | ,units="mg/kg") 34 | ordinalizer <- function(MTDi, r0 = 1.5) 35 | MTDi * r0 ^ c(Gr1=-2, Gr2=-1, Gr3=0, Gr4=1, Gr5=2) 36 | old <- options(dose_levels = c(0.5, 1, 2, 4, 6) 37 | ,ordinalizer = ordinalizer) 38 | get_boin(num_doses = 5, target = 0.25) \%>\% 39 | stop_at_n(n = 24) \%>\% 40 | simulate_trials( 41 | num_sims = 60 42 | , true_prob_tox = mtdi_gen) -> boin_hsims 43 | safety <- summary(boin_hsims)$safety 44 | safety # The print method invokes 'format.safetytab' .. 45 | # .. but we can also inspect the underlying matrix by indexing: 46 | safety[,] # indexing strips 'safetytab' class, returning plain matrix 47 | # Note that, by extend()ing the simulation we can increase precision: 48 | if (interactive()) { # may run a bit too long for CRAN servers' taste 49 | boin_hsims \%>\% extend(target_mcse = 0.1) -> boin_hsimsX 50 | summary(boin_hsimsX)$safety 51 | } 52 | options(old) 53 | } 54 | -------------------------------------------------------------------------------- /man/hyper_mtdi_lognormal-class.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/toxicity_generators.R 3 | \docType{class} 4 | \name{hyper_mtdi_lognormal-class} 5 | \alias{hyper_mtdi_lognormal-class} 6 | \alias{hyper_mtdi_lognormal} 7 | \title{Hyperprior for lognormal MTDi distributions} 8 | \description{ 9 | This hyperprior generates lognormal MTDi distributions with their 10 | coefficients of variation being drawn from a Rayleigh distribution 11 | with mode parameter set to 12 | \deqn{\sigma := CV.} 13 | Because the standard deviation of this distribution is 14 | \deqn{sd = \sigma \sqrt{(2 - \pi/2)} \approx 0.655 \sigma,}{% 15 | sd = \sigma \sqrt(2 - \pi/2) ~ 0.655 \sigma,} 16 | this conveniently links our uncertainty about \code{CV} to its \emph{mode}, 17 | and indeed to other measures of centrality that are proportional to this: 18 | \deqn{mean = \sigma \sqrt{\pi/2} \approx 1.25 \sigma}{% 19 | mean = \sigma \sqrt(\pi/2) ~ 1.25 \sigma} 20 | 21 | \deqn{median = \sigma \sqrt{2 log(2)} \approx 1.18 \sigma.}{% 22 | median = \sigma \sqrt(2 log(2)) ~ 1.18 \sigma.} 23 | The \emph{medians} of the lognormal distributions generated are themselves 24 | drawn from a lognormal distribution with \code{meanlog = log(median_mtd)} 25 | and \code{sdlog = median_sdlog}. Thus, parameter \code{median_sdlog} 26 | represents a proportional uncertainty in \code{median_mtd}. 27 | } 28 | \section{Slots}{ 29 | 30 | \describe{ 31 | \item{\code{CV}}{Coefficient of variation} 32 | 33 | \item{\code{median_mtd}}{Median MTDi} 34 | 35 | \item{\code{median_sdlog}}{Proportional uncertainty in median MTDi} 36 | }} 37 | 38 | -------------------------------------------------------------------------------- /man/mtdi_lognormal-class.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/toxicity_generators.R 3 | \docType{class} 4 | \name{mtdi_lognormal-class} 5 | \alias{mtdi_lognormal-class} 6 | \alias{mtdi_lognormal} 7 | \title{A lognormal MTDi distribution} 8 | \description{ 9 | A lognormal MTDi distribution 10 | } 11 | \section{Slots}{ 12 | 13 | \describe{ 14 | \item{\code{dist}}{A list with \code{cdf}, \code{quantile} and \code{name} components 15 | intended to provide that portion of the interface of \code{distr6::Lognormal}.} 16 | }} 17 | 18 | -------------------------------------------------------------------------------- /man/ordinalizer.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/precautionary-package.R 3 | \name{ordinalizer} 4 | \alias{ordinalizer} 5 | \alias{ordinalizers} 6 | \alias{ordinalization} 7 | \title{Ordinalizers} 8 | \description{ 9 | TODO: Explain ordinalization and ordinalizers here. 10 | } 11 | \section{Limitations}{ 12 | 13 | TODO: Be sure to note the highly restrictive assumptions made about 14 | ordinalizer functions, especially as noted e.g. in connection with 15 | the internal function G (defined in 'exact.R'). 16 | } 17 | 18 | \section{Validity}{ 19 | 20 | The validity of an ordinalizer might well be programmatically testable. 21 | If so, all this discussion might well be carried out in documentation 22 | for a validity-testing function. 23 | } 24 | 25 | -------------------------------------------------------------------------------- /man/phase1_sim.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/enhance.R 3 | \name{phase1_sim} 4 | \alias{phase1_sim} 5 | \title{Override \code{escalation:::phase1_sim} to incorporate latent toxicity tolerances} 6 | \usage{ 7 | phase1_sim( 8 | selector_factory, 9 | true_prob_tox, 10 | sample_patient_arrivals = function(df) cohorts_of_n(n = 3, mean_time_delta = 1), 11 | previous_outcomes = "", 12 | next_dose = NULL, 13 | i_like_big_trials = FALSE, 14 | return_all_fits = FALSE 15 | ) 16 | } 17 | \arguments{ 18 | \item{selector_factory}{A \code{\link[escalation]{selector_factory}} object} 19 | 20 | \item{true_prob_tox}{A vector of toxicity probabilities for the doses 21 | defined in \code{selector_factory}} 22 | 23 | \item{sample_patient_arrivals}{A function implementing an arrivals process 24 | for trial enrollment} 25 | 26 | \item{previous_outcomes}{This may or may not apply in applications of 27 | package \code{precautionary}} 28 | 29 | \item{next_dose}{Undocumented} 30 | 31 | \item{i_like_big_trials}{I didn't choose this parameter name} 32 | 33 | \item{return_all_fits}{Don't do this} 34 | } 35 | \description{ 36 | Override \code{escalation:::phase1_sim} to incorporate latent toxicity tolerances 37 | } 38 | -------------------------------------------------------------------------------- /man/plan.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/precautionary-package.R 3 | \name{plan} 4 | \alias{plan} 5 | \alias{todo} 6 | \title{Plan} 7 | \description{ 8 | Plan 9 | } 10 | \section{Version 0.2.6-1}{ 11 | 12 | \itemize{ 13 | \item Improve EscRisk app feedback during long calculations 14 | \itemize{ 15 | \item Set J = '...' pending first progress report 16 | \item Analyze where \code{Cpe$path_array()} spends time 17 | \item Give suitable feedback on \code{path_array} progress 18 | } 19 | \item Correct Rust-related complaints from CRAN 20 | \item Restore Windows build & check on 'main' branch 21 | \item Add citations to CPE vignette(s) 22 | \itemize{ 23 | \item Lin & Shih 2001 24 | \item Reiner, Paoletti & O'Quigley 1999 25 | \item ?others as referenced in the above? 26 | } 27 | } 28 | } 29 | 30 | \section{Version 0.2.7}{ 31 | 32 | \itemize{ 33 | \item Demote \pkg{escalation} to a 'Suggests' 34 | \item Thoroughly rewrite 'Intro' and 'FDA Clinical Hold' vignettes 35 | } 36 | } 37 | 38 | \section{Version 0.2.8}{ 39 | 40 | \itemize{ 41 | \item BOIN recs via isotonic regression 42 | \item Test-that CPE matches \code{BOIN::get.oc()} sim 43 | \item Implement CRM logistic model 44 | } 45 | } 46 | 47 | \section{Version 0.2.9}{ 48 | 49 | \itemize{ 50 | \item Implement TITE CRM? 51 | \itemize{ 52 | \item Is TITE even amenable to path enumeration? 53 | \item If not, there may be little sense in implementing it here! 54 | \item If TITE is truly off the table, can existing numerics be 55 | sped up further? 56 | \item OTOH, implementing TITE would help place the numerics 57 | for enumerable designs in context. 58 | } 59 | } 60 | } 61 | 62 | \section{Version 0.3.0}{ 63 | 64 | \itemize{ 65 | \item Stop exposing the \code{impl} parameter 66 | } 67 | } 68 | 69 | \section{Version 0.3.1}{ 70 | 71 | \itemize{ 72 | \item Native Rust CPE 73 | } 74 | } 75 | 76 | \section{Dependencies}{ 77 | 78 | \itemize{ 79 | \item Eliminate dependence on/adherence to \code{dtpcrm} layout 80 | \itemize{ 81 | \item Package \code{dtpcrm} makes many design decisions unsuited to 82 | comprehensive enumeration of whole trials. 83 | \item Allowing the \code{Crm} class to evolve along now-'natural' lines 84 | probably makes a suitable 'plan' for now. 85 | \item Expunging superseded code/dependencies ASAP will facilitate 86 | this evolution. 87 | \item Even the term 'DTP' seems not quite right anymore for a complete 88 | path enumeration (CPE?), and should be abandoned. 89 | } 90 | \item Eliminate dependence on \code{escalation} and \code{dfcrm} 91 | \itemize{ 92 | \item With the special emphasis on \emph{speed} created by CPE, 93 | I now must implement all underlying trial designs in Rust. 94 | } 95 | \item What may be retained in each case are 'Suggests:'-type relations, 96 | wherever regression tests are helpful -- esp. wrt \code{dfcrm}. 97 | } 98 | } 99 | 100 | \section{Fast CRM}{ 101 | 102 | \itemize{ 103 | \item Benchmark; try \code{mul_add()}s 104 | } 105 | } 106 | 107 | \section{Document}{ 108 | 109 | \itemize{ 110 | \item Add examples to the documented Rust functions 111 | \item Add a vignette applying DTP to mTPI and BOIN 112 | \item Expose some visual numerics checks, via vignette or documented function 113 | } 114 | } 115 | 116 | \section{Refactor}{ 117 | 118 | \itemize{ 119 | \item Remove the \verb{$safety} component of exact trials? 120 | \itemize{ 121 | \item Perhaps this ought to be calculated 'on the fly' by the summary method. 122 | \item On-the-fly calculation would postpone use of ordinalizer, in keeping with 123 | the pattern established already for (non-exact) simulations. 124 | } 125 | \item Should summary(EXACT)$safety bear class 'safetytab'? 126 | \item Example for 'as.data.table.exact' 127 | \item What is role of G function in exact.R? 128 | } 129 | } 130 | 131 | \section{Extend}{ 132 | 133 | \itemize{ 134 | \item Implement exact 3+3 variant with \code{allow_deescalation=FALSE} 135 | \item Implement rolling 6 136 | \item Allow an accelerated titration phase 137 | \itemize{ 138 | \item Note that this requires access to graded toxicities at simulation time, 139 | and therefore constitutes a substantial challenge to the generalizability 140 | of this software design. 141 | } 142 | \item Index \code{sims$fits} to exact outcomes in \code{A[[D]]} where appropriate 143 | \itemize{ 144 | \item See the \code{haystack} function in \code{exact.R} 145 | } 146 | } 147 | } 148 | 149 | \section{Robustness}{ 150 | 151 | \itemize{ 152 | \item Tests comparing results from multiple CRAN packages 153 | } 154 | } 155 | 156 | -------------------------------------------------------------------------------- /man/plot-mtdi_distribution-ANY-method.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/toxicity_generators.R 3 | \name{plot,mtdi_distribution,ANY-method} 4 | \alias{plot,mtdi_distribution,ANY-method} 5 | \title{Visualize an \code{mtdi_distribution} object} 6 | \usage{ 7 | \S4method{plot}{mtdi_distribution,ANY}(x, y = NULL, ...) 8 | } 9 | \arguments{ 10 | \item{x}{An \code{mtdi_distribution} object} 11 | 12 | \item{y}{Included for compatibility with generic signature} 13 | 14 | \item{\dots}{Additional arguments passed onward to \code{plot}} 15 | } 16 | \description{ 17 | Visualize an \code{mtdi_distribution} object 18 | } 19 | \examples{ 20 | if (interactive()) { 21 | mtdi_dist <- mtdi_lognormal(CV = 2 22 | ,median = 5 23 | ,units = "mg/kg") 24 | # Setting pre-specified dose levels via options() causes 25 | # toxicity probabilities to be annotated on the plot. 26 | old <- options(dose_levels = c(0.5, 1, 2, 4, 6)) 27 | plot(mtdi_dist, col = "red") 28 | options(old) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /man/plot-mtdi_generator-ANY-method.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/toxicity_generators.R 3 | \name{plot,mtdi_generator,ANY-method} 4 | \alias{plot,mtdi_generator,ANY-method} 5 | \title{Visualize n samples from an \code{mtdi_generator} object} 6 | \usage{ 7 | \S4method{plot}{mtdi_generator,ANY}(x, y = NULL, n = 20, col = "gray", ...) 8 | } 9 | \arguments{ 10 | \item{x}{An \code{mtdi_generator} object} 11 | 12 | \item{y}{Included for compatibility with generic signature} 13 | 14 | \item{n}{Number of samples to draw from hyperprior for visualization} 15 | 16 | \item{col}{Color of lines used to depict samples} 17 | 18 | \item{\dots}{Additional arguments passed onward to \code{plot}} 19 | } 20 | \description{ 21 | Visualize n samples from an \code{mtdi_generator} object 22 | } 23 | \examples{ 24 | if (interactive()) { 25 | mtdi_gen <- hyper_mtdi_lognormal(CV = 1 26 | ,median_mtd = 5 27 | ,median_sdlog = 0.5 28 | ,units="mg/kg") 29 | plot(mtdi_gen, n=100, col=adjustcolor("red", alpha=0.5)) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /man/plot_dutycycle.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/dutycycle.R 3 | \name{plot_dutycycle} 4 | \alias{plot_dutycycle} 5 | \title{Plot duty cycle from performance report on a parallel computation} 6 | \usage{ 7 | plot_dutycycle(perftab, ..., FUN = c(workers = sum), layout = c(1, NA)) 8 | } 9 | \arguments{ 10 | \item{perftab}{A performance table with columns: 11 | \itemize{ 12 | \item \code{pid} An integer, character or factor with process ids 13 | \item \code{t1}, \code{t2} Task start and end times, in milliseconds 14 | }} 15 | 16 | \item{...}{Optional parameters passed along to \code{lattice::xyplot}} 17 | 18 | \item{FUN}{A function for summarizing all workers' duty cycles} 19 | 20 | \item{layout}{Trellis layout, passed to \code{xyplot}} 21 | } 22 | \value{ 23 | An \code{xyplot} with a duty-cycle panel for each worker, 24 | plus an overall average 25 | } 26 | \description{ 27 | This is intended for application to the tables which get attached 28 | to \code{Cpe} instances after invocation of the \verb{$trace_paths()} method. 29 | But any table with columns named \code{pid}, \code{t1} and \code{t2} suffices. 30 | } 31 | \examples{ 32 | if (interactive()) { 33 | ## Example from Braun2020 34 | d1_maxn <- 5 35 | cum_maxn <- 10 36 | mod <- Crm$new(skeleton = c(0.03, 0.11, 0.25, 0.42, 0.58, 0.71), 37 | scale = 0.85, # aka 'sigma' 38 | target = 0.25)$ 39 | no_skip_esc(TRUE)$ # compare Braun's 'restrict = T' 40 | no_skip_deesc(FALSE)$ 41 | stop_func(function(x) { 42 | enrolled <- tabulate(x$level, nbins = length(x$prior)) 43 | x$stop <- enrolled[1] >= d1_maxn || max(enrolled) >= cum_maxn 44 | x 45 | }) 46 | mod$trace_paths(1, rep(2, 13), unroll = 4 47 | , mc.cores = parallelly::availableCores(omit=2)) 48 | print(mod$performance) 49 | plot_dutycycle(mod$performance) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /man/precautionary-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/precautionary-package.R 3 | \docType{package} 4 | \name{precautionary-package} 5 | \alias{precautionary-package} 6 | \alias{precautionary} 7 | \title{Safety Diagnostics for Dose-Escalation Trial Designs} 8 | \description{ 9 | Enhances various R packages that support the design and simulation 10 | of phase 1 dose-escalation trials, adding diagnostics to examine the safety 11 | characteristics of these designs in light of expected inter-individual variation 12 | in pharmacokinetics and pharmacodynamics. 13 | } 14 | \references{ 15 | \enumerate{ 16 | \item Norris DC. Dose Titration Algorithm Tuning (DTAT) should supersede 17 | \sQuote{the} Maximum Tolerated Dose (MTD) in oncology dose-finding trials. 18 | \emph{F1000Research}. 2017;6:112. \doi{10.12688/f1000research.10624.3}. 19 | \url{https://f1000research.com/articles/6-112/v3} 20 | \item Norris DC. Costing \sQuote{the} MTD. \emph{bioRxiv}. August 2017:150821. 21 | \doi{10.1101/150821}. 22 | \url{https://www.biorxiv.org/content/10.1101/150821v3} 23 | \item Norris DC. Precautionary Coherence Unravels Dose Escalation Designs. 24 | \emph{bioRxiv}. December 2017:240846. \doi{10.1101/240846}. 25 | \url{https://www.biorxiv.org/content/10.1101/240846v1} 26 | \item Norris DC. One-size-fits-all dosing in oncology wastes money, innovation 27 | and lives. \emph{Drug Discovery Today}. 2018;23(1):4-6. 28 | \doi{10.1016/j.drudis.2017.11.008}. 29 | \url{https://www.sciencedirect.com/science/article/pii/S1359644617303586} 30 | \item Norris DC. Costing \sQuote{the} MTD ... in 2-D. \emph{bioRxiv}. July 2018:370817. 31 | \doi{10.1101/370817}. 32 | \url{https://www.biorxiv.org/content/10.1101/370817v1} 33 | \item Norris DC. Ethical Review and Methodologic Innovation in Phase 1 Cancer Trials. 34 | \emph{JAMA Pediatrics}. 2019;173(6):609 35 | \doi{10.1001/jamapediatrics.2019.0811}. 36 | \item Norris DC. Comment on Wages et al., Coherence principles in interval-based 37 | dose finding. Pharmaceutical Statistics 2019, DOI: 10.1002/pst.1974. 38 | \emph{Pharmaceutical Statistics}. March 2020. 39 | \doi{10.1002/pst.2016}. 40 | \item Norris DC. Retrospective analysis of a fatal dose-finding trial. 41 | arXiv:2004.12755 [stat.ME]. April 2020. 42 | \url{https://arxiv.org/abs/2004.12755} 43 | \item Norris DC. What Were They Thinking? Pharmacologic priors implicit in a choice 44 | of 3+3 dose-escalation design. arXiv:2012.05301 [stat.ME]. December 2020. 45 | \url{https://arxiv.org/abs/2012.05301} 46 | } 47 | } 48 | \author{ 49 | David C. Norris (\url{https://orcid.org/0000-0001-9593-6343}) 50 | } 51 | -------------------------------------------------------------------------------- /man/print.exact.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/exact.R 3 | \name{print.exact} 4 | \alias{print.exact} 5 | \title{Specialize print method for objects of class \code{\link[escalation]{simulations}}} 6 | \usage{ 7 | \method{print}{exact}(x, ...) 8 | } 9 | \arguments{ 10 | \item{x}{An object of class c("exact","precautionary","simulations")} 11 | 12 | \item{...}{Additional arguments; ignored} 13 | } 14 | \description{ 15 | Specialize print method for objects of class \code{\link[escalation]{simulations}} 16 | } 17 | -------------------------------------------------------------------------------- /man/print.hyper.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/enhance.R, R/exact.R 3 | \name{print.hyper} 4 | \alias{print.hyper} 5 | \title{Specialize print method defined for class \code{\link[escalation]{simulations}}} 6 | \usage{ 7 | \method{print}{hyper}(x, ...) 8 | 9 | \method{print}{hyper}(x, ...) 10 | } 11 | \arguments{ 12 | \item{x}{An object of class c("hyper","precautionary","simulations")} 13 | 14 | \item{...}{Additional arguments; ignored} 15 | } 16 | \description{ 17 | Specialize print method defined for class \code{\link[escalation]{simulations}} 18 | 19 | Specialize print method defined for class \code{\link[escalation]{simulations}} 20 | } 21 | -------------------------------------------------------------------------------- /man/print.precautionary.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/enhance.R 3 | \name{print.precautionary} 4 | \alias{print.precautionary} 5 | \title{Specialize print method for objects of class \code{\link[escalation]{simulations}}} 6 | \usage{ 7 | \method{print}{precautionary}(x, ...) 8 | } 9 | \arguments{ 10 | \item{x}{An object of class c("precautionary","simulations")} 11 | 12 | \item{...}{Additional arguments; ignored} 13 | } 14 | \description{ 15 | Specialize print method for objects of class \code{\link[escalation]{simulations}} 16 | } 17 | -------------------------------------------------------------------------------- /man/safety_kable.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/enhance.R 3 | \name{safety_kable} 4 | \alias{safety_kable} 5 | \title{Output a \code{kable} for a simulation summary of class \code{safetytab}} 6 | \usage{ 7 | safety_kable(safetytab, ...) 8 | } 9 | \arguments{ 10 | \item{safetytab}{An object of S3 class \code{safetytab}} 11 | 12 | \item{...}{Additional parameters passed to \link[knitr:kable]{knitr::kable}} 13 | } 14 | \description{ 15 | Output a \code{kable} for a simulation summary of class \code{safetytab} 16 | } 17 | -------------------------------------------------------------------------------- /man/simulation_function.u_i.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/enhance.R 3 | \name{simulation_function.u_i} 4 | \alias{simulation_function.u_i} 5 | \title{Get a function that simulates dose-escalation trials using latent \code{u_i}} 6 | \usage{ 7 | \method{simulation_function}{u_i}(selector_factory) 8 | } 9 | \arguments{ 10 | \item{selector_factory}{Presently, this must be a \code{tox_selector_factory}; 11 | no equivalent for \code{simulation_function.derived_dose_selector_factory} 12 | is yet implemented.} 13 | } 14 | \description{ 15 | Overrides \code{\link[escalation:simulation_function]{simulation_function.tox_selector_factory}} 16 | to return a \code{\link[=phase1_sim]{phase1_sim()}} that employs latent \code{u_i} in place of 17 | the version native to package \CRANpkg{escalation}, which merely invokes 18 | \code{rbinom}. 19 | } 20 | \details{ 21 | This function is exported for the purpose of effecting this override, 22 | and is not meant to be invoked directly by the user. 23 | } 24 | -------------------------------------------------------------------------------- /man/stop_for_excess_toxicity_empiric.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/dtp.R 3 | \name{stop_for_excess_toxicity_empiric} 4 | \alias{stop_for_excess_toxicity_empiric} 5 | \title{A supremely faster version of a function from \code{dtpcrm} v0.1.1} 6 | \usage{ 7 | stop_for_excess_toxicity_empiric( 8 | x, 9 | tox_lim, 10 | prob_cert, 11 | dose = 1, 12 | suppress_dose = TRUE 13 | ) 14 | } 15 | \arguments{ 16 | \item{x}{A object of class \code{mtd}} 17 | 18 | \item{tox_lim}{Scalar upper threshold on estimated toxicity rate} 19 | 20 | \item{prob_cert}{Confidence level for threshold exceedance} 21 | 22 | \item{dose}{Integer scalar, the dose being considered} 23 | 24 | \item{suppress_dose}{Logical; if TRUE the MTD is set to \code{NA} when 25 | trial stop is recommended.} 26 | } 27 | \value{ 28 | The \code{mtd} object x, with stop decision annotated 29 | } 30 | \description{ 31 | Originally, the sampling in \code{stats::rnorm()} (see inline comments in code) 32 | consumed 53\% of run-time in a 6-cohort VIOLA DTP. After this change, it 33 | doesn't even show up! More importantly, the consumption is now dominated 34 | by (at 75\%) by the objective function 'f' in integrate(). 35 | } 36 | \author{ 37 | Adapted by David C. Norris from original \code{dtpcrm::stop_for_excess_toxicity_empiric} 38 | } 39 | -------------------------------------------------------------------------------- /man/summary.exact.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/exact.R 3 | \name{summary.exact} 4 | \alias{summary.exact} 5 | \title{Summarize an exact treatment of a dose-escalation design} 6 | \usage{ 7 | \method{summary}{exact}(object, ordinalizer = getOption("ordinalizer"), ...) 8 | } 9 | \arguments{ 10 | \item{object}{An object of class 'exact'} 11 | 12 | \item{ordinalizer}{An ordinalizer function} 13 | 14 | \item{...}{Additional parameters passed to the ordinalizer} 15 | } 16 | \description{ 17 | Algorithmic (or 'rule-based') dose-escalation designs admit exact computation 18 | of their outcomes. This method summarizes such an exact treatment in a manner 19 | roughly parallel to that of \code{summary.precautionary}. 20 | } 21 | -------------------------------------------------------------------------------- /man/summary.precautionary.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/enhance.R 3 | \name{summary.precautionary} 4 | \alias{summary.precautionary} 5 | \title{Specialize a method defined in package 'escalation' for class 'simulations'} 6 | \usage{ 7 | \method{summary}{precautionary}(object, ordinalizer = getOption("ordinalizer"), ...) 8 | } 9 | \arguments{ 10 | \item{object}{An object of class c('precautionary','simulations')} 11 | 12 | \item{ordinalizer}{An ordinalizer function} 13 | 14 | \item{...}{Additional parameters passed to the ordinalizer} 15 | } 16 | \description{ 17 | Simulations produced by package \code{precautionary} incorporate a \sQuote{u_i} 18 | latent toxicity tolerance that characterizes the toxic dose-response of each 19 | simulated individual trial participant. In conjunction with an 20 | \sQuote{ordinalizer} function, these extra data enable questions to be asked 21 | about trial safety, in terms of the probabilities of high-grade toxicities. 22 | This function specializes the \code{escalation:::summary.simulations} method 23 | accordingly. 24 | } 25 | -------------------------------------------------------------------------------- /man/test_draw_samples.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/toxicity_generators.R 3 | \name{test_draw_samples} 4 | \alias{test_draw_samples} 5 | \title{Test performance of \code{draw_samples} function} 6 | \usage{ 7 | test_draw_samples(n = 500) 8 | } 9 | \arguments{ 10 | \item{n}{Number of samples to draw} 11 | } 12 | \description{ 13 | Test performance of \code{draw_samples} function 14 | } 15 | -------------------------------------------------------------------------------- /man/viola_dtp.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{viola_dtp} 5 | \alias{viola_dtp} 6 | \title{Complete dose transition pathways (DTP) table for the VIOLA trial.} 7 | \format{ 8 | A data frame with 4^7 = 16384 rows and 15 columns, each row 9 | representing one possible path the trial could take: 10 | \describe{ 11 | \item{D0}{Initial dose level} 12 | \item{T1}{Number of toxicities observed in first cohort} 13 | \item{D1}{Dose recommendation after the first cohort} 14 | \item{T2}{Number of toxicities observed in second cohort} 15 | \item{D2}{Dose recommendation after the second cohort} 16 | \item{T3}{Number of toxicities observed in third cohort} 17 | \item{D3}{Dose recommendation after the third cohort} 18 | \item{T4}{Number of toxicities observed in fourth cohort} 19 | \item{D4}{Dose recommendation after the fourth cohort} 20 | \item{T5}{Number of toxicities observed in fifth cohort} 21 | \item{D5}{Dose recommendation after the fifth cohort} 22 | \item{T6}{Number of toxicities observed in sixth cohort} 23 | \item{D6}{Dose recommendation after the sixth cohort} 24 | \item{T7}{Number of toxicities observed in seventh cohort} 25 | \item{D7}{Dose recommendation after the seventh cohort} 26 | } 27 | } 28 | \usage{ 29 | viola_dtp 30 | } 31 | \description{ 32 | This data set caches a long computation (17 minutes on a 2.6GHz i7) 33 | needed to build one package vignette. 34 | } 35 | \seealso{ 36 | Documentation of the \code{\link[dtpcrm]{calculate_dtps}} function. 37 | } 38 | \keyword{datasets} 39 | -------------------------------------------------------------------------------- /pkgdown/_pkgdown.yml: -------------------------------------------------------------------------------- 1 | home: 2 | title: Safety Diagnostics for Dose Escalation 3 | description: > 4 | Patient-centered safety diagnostics for 5 | oncology dose-escalation trials, accounting 6 | for inter-individual variation in PKPD. 7 | 8 | development: 9 | mode: unreleased 10 | 11 | url: https://dcnorris.github.io/precautionary/ 12 | 13 | template: 14 | opengraph: 15 | image: 16 | src: https://github.com/dcnorris/precautionary/raw/main/docs/card.png 17 | alt: "Logo for precautionary package" 18 | twitter: 19 | creator: "@davidcnorrismd" 20 | card: summary 21 | -------------------------------------------------------------------------------- /precautionary.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | BuildType: Package 16 | PackageUseDevtools: Yes 17 | PackageInstallArgs: --no-multiarch --with-keep.source 18 | PackageRoxygenize: rd,collate,namespace 19 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | *.dll 4 | target 5 | Cargo.lock 6 | -------------------------------------------------------------------------------- /src/Makevars: -------------------------------------------------------------------------------- 1 | LIBDIR = ./rust/target/release 2 | STATLIB = $(LIBDIR)/libprecautionary.a 3 | PKG_LIBS = -L$(LIBDIR) -lprecautionary 4 | 5 | #all: clean 6 | $(SHLIB): $(STATLIB) 7 | 8 | # CRAN forbids writing $HOME and mandates wiping .cargo after each use 9 | CARGO_HOME = $(PWD)/.cargo 10 | export CARGO_HOME 11 | 12 | # TODO: Do I need 'cargo build --lib --release ...' below (i.e., should I add '--lib')? 13 | # OR.. is it possible that my earlier build efforts were stumbling on this point? 14 | 15 | $(STATLIB): 16 | PATH="$(HOME)/.cargo/bin:$(PATH)" cargo build --lib --release --manifest-path=./rust/Cargo.toml 17 | rm -Rf $(CARGO_HOME) 18 | rm -Rf $(LIBDIR)/build 19 | 20 | clean: 21 | rm -Rf $(SHLIB) $(STATLIB) $(OBJECTS) rust/target 22 | -------------------------------------------------------------------------------- /src/Makevars.win: -------------------------------------------------------------------------------- 1 | TARGET = $(subst 64,x86_64,$(subst 32,i686,$(WIN)))-pc-windows-gnu 2 | LIBDIR = ./rust/target/$(TARGET)/release 3 | STATLIB = $(LIBDIR)/libprecautionary.a 4 | PKG_LIBS = -L$(LIBDIR) -lprecautionary -lws2_32 -ladvapi32 -luserenv 5 | 6 | # These can also be set in ~/.cargo/config 7 | #export CARGO_TARGET_I686_PC_WINDOWS_GNU_LINKER=C:\\rtools40\\mingw$(WIN)\\bin\\gcc 8 | #export CC=$(CC) 9 | #export AR=$(AR) 10 | 11 | # This bypasses the exception stuff 12 | #export CARGO_TARGET_I686_PC_WINDOWS_GNU_RUSTFLAGS=-C panic=abort 13 | 14 | GCCPATH=$(subst C:\,/c/,$(RTOOLS40_HOME))/mingw$(WIN)/bin 15 | 16 | all: clean 17 | 18 | $(SHLIB): $(STATLIB) 19 | 20 | $(STATLIB): 21 | PATH="$(GCCPATH):$(PATH)" cargo build --target=$(TARGET) --lib --release --manifest-path=./rust/Cargo.toml 22 | 23 | clean: 24 | rm -Rf $(SHLIB) $(STATLIB) $(OBJECTS) rust/target 25 | -------------------------------------------------------------------------------- /src/entrypoint.c: -------------------------------------------------------------------------------- 1 | // We need to forward routine registration from C to Rust 2 | // to avoid the linker removing the static library. 3 | 4 | void R_init_precautionary_extendr(void *dll); 5 | 6 | void R_init_precautionary(void *dll) { 7 | R_init_precautionary_extendr(dll); 8 | } 9 | -------------------------------------------------------------------------------- /src/rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = 'precautionary' 3 | version = '0.1.0' 4 | edition = '2018' 5 | [lib] 6 | crate-type = [ 'staticlib' ] 7 | [dependencies] 8 | extendr-api = '*' 9 | peroxide = "0.30" -------------------------------------------------------------------------------- /src/rust/src/lib.rs: -------------------------------------------------------------------------------- 1 | use extendr_api::prelude::*; 2 | 3 | #[allow(non_snake_case)] 4 | 5 | #[inline(always)] 6 | fn crmh_non(exp_a_: &f64, // NB: *NOT* vectorized 7 | ln_x: &[f64], // the log-skeleton, patient-wise 8 | w: &[f64]) -> f64 { 9 | // The non-tox factor is the nontrivial part of the CRM power model integrand, 10 | // because ln does not commute with any operations inside (1 - w * x^exp_a_). 11 | // By encoding y in w (via w==0.0 iff y==1), however, we can make the scan 12 | // straightforward. 13 | // It is also possible to skip some exp()'s in this loop, by sorting patients 14 | // (i.e., ln_x's and w's) before entry, to make the ln_x's contiguous. 15 | let mut ln_x_ = ln_x[0]; 16 | let mut p_ = (ln_x_*exp_a_).exp(); 17 | let mut v_non = 1.0 - w[0]*p_; 18 | for i in 1 .. w.len() { 19 | if w[i] > 0.0 { // This 'guard' is not necessary for correctness ... 20 | if ln_x[i] != ln_x_ { 21 | ln_x_ = ln_x[i]; 22 | p_ = (ln_x_*exp_a_).exp(); // TXOP 23 | } // (above recalc gets skipped often if ln_x contiguous) 24 | v_non *= 1.0 - w[i]*p_; // ... because w[i]==0 case gives *= 1.0 here. 25 | } // This guard's performance impacts are TBD, and likely data-dependent. 26 | } 27 | 28 | v_non 29 | } 30 | 31 | // Vectorize crmh1 on the 'a' parameter 32 | fn crmh_v(a: &[f64], 33 | ln_x: &[f64], // patient-wise log-skeleton 34 | w: &[f64], // patient-wise weights; tox iff 0.0 35 | s: f64, 36 | b: i32) -> Robj { 37 | 38 | // We can calculate the toxic term irrespective of 'a', 39 | // except for its exp(a) factor which we multiply on at the end. 40 | let mut log_vtox = 0.0; 41 | for i in 0 .. w.len() { 42 | if w[i] == 0.0 { // iterate over toxicities 43 | log_vtox += ln_x[i]; 44 | } 45 | } 46 | 47 | let v = a.iter().map(|a| if a > &709.0 { 0.0 } else { 48 | let log_g = -0.5 * (a/s).powi(2); 49 | let exp_a_ = a.exp(); 50 | crmh_non(&exp_a_,&ln_x,&w) 51 | * (log_g + exp_a_*log_vtox).exp() 52 | * a.powi(b) 53 | }); 54 | 55 | v.collect_robj() 56 | } 57 | 58 | /// Rust implementation of `dfcrm::crmh*` integrands for w==1 case 59 | /// 60 | /// @param a Numeric vector of evaluation points 61 | /// @param ln_x A numeric vector of dose-wise prior log-probabilities of toxicity 62 | /// @param tox A numeric vector; a dose-wise tally of toxicities 63 | /// @param nos A numeric vector; a dose-wise tally of non-toxicities 64 | /// @param s Scalar scale factor 65 | /// @param b Order of moment to calculate (0, 1 or 2) 66 | /// @export 67 | #[extendr] 68 | fn crmh_xo(a: &[f64], 69 | ln_x: &[f64], // DOSE-WISE log-skeleton -- different from crmh_v! 70 | tox: &[i32], 71 | nos: &[i32], 72 | s: f64, 73 | b: i32) -> Robj { 74 | 75 | // As in crmh_v, this calculation is something that could be done 76 | // by the caller. But note that, with ln_x being here DOSE-INDEXED, 77 | // the proper approach to the calculation is somewhat different. 78 | // So I demonstrate that approach here for the caller's benefit. 79 | let mut log_vtox = 0.0; 80 | for d in 0 .. ln_x.len() { 81 | log_vtox += ln_x[d] * tox[d] as f64; // TODO: mul_add 82 | } 83 | 84 | let v = a.iter().map(|a| if a > &709.0 { 0.0 } else { 85 | let log_g = -0.5 * (a/s).powi(2); 86 | let exp_a_ = a.exp(); 87 | let o_factor = { // x/o-notation-inspired name for 'non-tox factor' 88 | let mut nontox_ = 1.0; 89 | for d in 0 .. ln_x.len() { 90 | if nos[d] > 0 { // skip over any 100%-toxic dose 91 | let p_d = (ln_x[d]*exp_a_).exp(); // TXOP 92 | nontox_ *= (1.0 - p_d).powi(nos[d]); 93 | } 94 | } 95 | nontox_ 96 | }; 97 | let x_term = log_g + exp_a_*log_vtox; 98 | o_factor * x_term.exp() * a.powi(b) 99 | }); 100 | 101 | v.collect_robj() 102 | } 103 | 104 | /// Rust implementation of `dfcrm::crmh*` integrands 105 | /// 106 | /// @param a Numeric vector of evaluation points 107 | /// @param ln_x A numeric vector of dose-wise prior log-probabilities of toxicity 108 | /// @param w Patient-wise weights (used for TITE CRM), also encoding toxicity 109 | /// by `w[i] == 0.0`. 110 | /// @param s Scalar scale factor 111 | /// @describeIn crmh Posterior for 1-parameter empiric (aka 'power') model 112 | /// @export 113 | #[extendr] 114 | fn crmh(a: &[f64], ln_x: &[f64], w: &[f64], s: f64) -> Robj { 115 | crmh_v(a, ln_x, w, s, 0) 116 | } 117 | 118 | /// @describeIn crmh Integrand for 1st moment of empiric posterior 119 | /// @export 120 | #[extendr] 121 | fn crmht(a: &[f64], ln_x: &[f64], w: &[f64], s: f64) -> Robj { 122 | crmh_v(a, ln_x, w, s, 1) 123 | } 124 | 125 | /// @describeIn crmh Integrand for 2nd moment of empiric posterior 126 | /// @export 127 | #[extendr] 128 | fn crmht2(a: &[f64], ln_x: &[f64], w: &[f64], s: f64) -> Robj { 129 | crmh_v(a, ln_x, w, s, 2) 130 | } 131 | 132 | // Macro to generate exports. 133 | // This ensures exported functions are registered with R. 134 | // See corresponding C code in `entrypoint.c`. 135 | extendr_module! { 136 | mod precautionary; 137 | fn crmh_xo; 138 | fn crmh; 139 | fn crmht; 140 | fn crmht2; 141 | } 142 | -------------------------------------------------------------------------------- /tests/manual/crm-numerics.R: -------------------------------------------------------------------------------- 1 | ## Compare the objective functions visually 2 | comp_objfn <- function(s = 500) { 3 | 4 | skeleton <- seq(0.1, 0.6, 0.1) 5 | 6 | ## cohort-wise set-up 7 | level <- c(1L, 2L, 3L, 2L, 3L, 3L) 8 | n_tox <- c(0L, 0L, 1L, 0L, 0L, 1L) 9 | obs <- encode_cohorts(enr = tabulate(level, nbins=8) 10 | ,tox = xtabs(n_tox ~ factor(level, levels=1:8), 11 | data=data.frame(n_tox = n_tox, 12 | level = level)) 13 | ) 14 | 15 | ## The 'dfcrm' & 'rusti' implementations take patient-wise vectors x and y, 16 | ## and patient-wise weights w that 'break exchangeability'. 17 | x <- skeleton[rep(level, each=3)] 18 | coh <- function(tox, n=3) c(rep(0L,n-tox), rep(1L,tox)) 19 | y <- as.integer(sapply(y, coh)) 20 | w <- rep(1,length(y)) 21 | w[y == 1] <- 0.0 # encode y in w for rusti's benefit (dfcrm is unaffected) 22 | 23 | a <- seq(-10, 10, 0.1) 24 | objectives <- data.table( 25 | u = a 26 | , dfcrm = dfcrm::crmh(a, x, y, w, s) 27 | , rusti = crmh(a, log(x), w, s) 28 | , ruste = crmh_ev(a, obs, log(skeleton), s, 0) 29 | ) 30 | 31 | ## Calculate deltas vs dfcrm::crmh 32 | deltas <- objectives 33 | deltas[, `:=`( 34 | rusti = rusti - dfcrm 35 | ,ruste = ruste - dfcrm 36 | )] 37 | 38 | ## Arrange this data frame *tall* 39 | talldata <- melt(deltas[,c('u','rusti','ruste')], measure.vars = c("rusti","ruste"), 40 | variable.name = "impl", value.name = "delta.f") 41 | 42 | Hmisc::xYplot(delta.f ~ u, groups = impl, data = talldata, 43 | type='l', auto.key=TRUE) 44 | } 45 | -------------------------------------------------------------------------------- /tests/manual/pending.R: -------------------------------------------------------------------------------- 1 | ## Manual tests go here, on the way to testthat/ dir 2 | 3 | viola_stop_func <- function(x) { 4 | y <- stop_for_excess_toxicity_empiric(x, 5 | tox_lim = 0.3, 6 | prob_cert = 0.72, 7 | dose = 1) 8 | if(y$stop){ 9 | x <- y 10 | } else { 11 | x <- stop_for_consensus_reached(x, req_at_mtd = 12) 12 | } 13 | } 14 | 15 | viola_prior <- c(0.03, 0.07, 0.12, 0.20, 0.30, 0.40, 0.52) 16 | 17 | test_viola_dtp <- function(scale = sqrt(0.75)) { 18 | timings <- list() 19 | outputs <- list() 20 | for (impl in c('dfcrm','rusti')) { 21 | timings[[impl]] <- system.time( 22 | outputs[[impl]] <- calculate_dtps(next_dose = 3, 23 | cohort_sizes = rep(3, 7), 24 | dose_func = applied_crm, 25 | prior = viola_prior, 26 | target = 0.2, 27 | stop_func = viola_stop_func, 28 | scale = scale, 29 | no_skip_esc = TRUE, 30 | no_skip_deesc = FALSE, 31 | global_coherent_esc = TRUE, 32 | impl = impl) 33 | ) 34 | } 35 | lookhere <<- list(timings = timings, outputs = outputs) 36 | return(timings) 37 | } 38 | 39 | 40 | ## Utility function 41 | moments <- function(levels, numtox, s = 500, prior = viola_prior) { 42 | x <- rep(prior[levels], each=3) 43 | y <- as.integer(t(t(matrix(1:3, nrow=3, ncol=length(levels))) <= numtox)) 44 | w <- rep(1, length(y)) 45 | 46 | integrals <- list( 47 | dfcrm = c(integrate(dfcrm::crmh, -Inf, Inf, x, y, w, s)$value 48 | ,integrate(dfcrm::crmht, -Inf, Inf, x, y, w, s)$value 49 | ,integrate(dfcrm::crmht2, -Inf, Inf, x, y, w, s)$value 50 | ) 51 | , Ri = c(integrate(precautionary:::crmh, -Inf, Inf, x, y, w, s)$value 52 | ,integrate(precautionary:::crmht, -Inf, Inf, x, y, w, s)$value 53 | ,integrate(precautionary:::crmht2, -Inf, Inf, x, y, w, s)$value 54 | ) 55 | , rusti = c(integrate(rcrmh, -Inf, Inf, x, y, w, s)$value 56 | ,integrate(rcrmht, -Inf, Inf, x, y, w, s)$value 57 | ,integrate(rcrmht2, -Inf, Inf, x, y, w, s)$value 58 | ) 59 | ) 60 | integrals <- do.call(rbind, integrals) 61 | colnames(integrals) <- paste0("m", 0:2) 62 | quad <- as.data.table(integrals, keep.rownames="impl") 63 | ## Let's compute some of the crm outputs ... 64 | quad[,`:=`( 65 | est = m1/m0 66 | ,e2 = m2/m0 67 | )] 68 | quad[, post.var := e2 - est^2] 69 | quad 70 | } 71 | 72 | ## There's a difference for D7 at index 95 73 | 74 | test_viola_95 <- function() { 75 | moments(levels = c(3, 4, 5, 6, 6, 6, 4), 76 | numtox = c(0, 0, 0, 1, 1, 3, 2)) 77 | } 78 | 79 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(precautionary) 3 | 4 | test_check("precautionary") 5 | -------------------------------------------------------------------------------- /tests/testthat/test-boin.R: -------------------------------------------------------------------------------- 1 | ## Independently corroborate BOIN CPE done in Prolog ... 2 | 3 | test_that("CPE for BOIN/CCD matches Prolog's BOIN25--6-24.tab", 4 | { 5 | D <- 4 6 | 7 | boin <- Boin$new(target = 0.25 8 | ,cohort_max = 6 9 | ,enroll_max = 24 10 | )$max_dose(D) 11 | 12 | paths <- boin$trace_paths( 13 | root_dose = 1, 14 | cohort_sizes = rep(1, 24), 15 | unroll=1 16 | )$path_matrix() 17 | 18 | ## For comparison with outputs of boin.pl, we transform 19 | ## the dtpcrm-shaped table 'paths' to tables of REC (T N){D}. 20 | 21 | J <- nrow(paths) 22 | pathvectors <- matrix(nrow = J, ncol = 1+2*D) 23 | colnames(pathvectors) <- c("rec", paste0(c("T","N"), rep(1:D, each=2))) 24 | 25 | for (j in 1:J) { 26 | dtpvec <- paths[j,] 27 | DTmtx <- matrix(dtpvec[-length(dtpvec)], nrow=2) 28 | doses <- DTmtx[1,] 29 | pathvectors[j,'rec'] <- -doses[doses <= 0][1] 30 | DTmtx <- DTmtx[,!is.na(colSums(DTmtx)), drop=FALSE] 31 | ## Now DTmtx pairs doses (row 1) with tox counts (row 2) 32 | N <- tabulate(DTmtx[1,], nbins=D) 33 | ## Sum the toxicities indexed by dose, including zero counts for non-tried doses: 34 | dose <- factor(DTmtx[1,], levels=1:D) 35 | ntox <- DTmtx[2,] 36 | T <- as.vector(xtabs(ntox ~ dose)) 37 | pathvectors[j,-1] <- as.vector(rbind(T,N)) 38 | } 39 | 40 | ## Since BOIN obtains its dose recommendation from isotonic regression, 41 | ## we ignore the recommendations yielded by the dose-escalation process. 42 | ## We focus our checks instead solely on the final cumulative tallies: 43 | r <- as.data.frame(pathvectors[,-1]) 44 | 45 | prolog <- read.table(system.file("testdata", sprintf("BOIN25-%d-6-24.tab", D) 46 | , package = "precautionary", mustWork = TRUE))[,-1] 47 | colnames(prolog) <- colnames(r) 48 | 49 | ## TODO: Generalize these constructions to arbitrary D 50 | rsols <- with(r, paste(paste(T1, N1, sep="/") 51 | ,paste(T2, N2, sep="/") 52 | ,paste(T3, N3, sep="/") 53 | ,paste(T4, N4, sep="/") 54 | )) 55 | psols <- with(prolog, paste(paste(T1, N1, sep="/") 56 | ,paste(T2, N2, sep="/") 57 | ,paste(T3, N3, sep="/") 58 | ,paste(T4, N4, sep="/") 59 | )) 60 | 61 | expect_identical(sort(rsols), sort(psols)) 62 | 63 | }) 64 | -------------------------------------------------------------------------------- /tests/testthat/test-enhance.R: -------------------------------------------------------------------------------- 1 | test_that("override of escalation::phase1_sim is nearly identical to original", { 2 | override_body <- body(precautionary:::phase1_sim) 3 | original_body <- body(escalation:::phase1_sim) 4 | override_lines <- deparse(override_body) 5 | # Scratch several opening lines that dup or retrieve unexported escalation functions 6 | override_lines <- grep("escalation::", override_lines[-(2:10)], invert = TRUE, value = TRUE) 7 | original_lines <- deparse(original_body) 8 | # Of course, tests such as the following are inherently fragile. 9 | # But they make the point that differences are small, and it is 10 | # nearly 'inconceivable' that they won't fail (thus alerting me) 11 | # upon any changes to the original code in package 'escalation'. 12 | expect_equal(length(override_lines) - 2, length(original_lines)) 13 | override_lines_omit_u_i <- grep("u_i", override_lines, invert = TRUE, value = TRUE) 14 | original_lines_omit_rbinom <- grep("rbinom", original_lines, invert = TRUE, value = TRUE) 15 | expect_equal(override_lines_omit_u_i, original_lines_omit_rbinom[-44]) 16 | }) 17 | -------------------------------------------------------------------------------- /tests/testthat/test-exact.R: -------------------------------------------------------------------------------- 1 | test_that("exact 3+3 ('more common variant') safety matches simulated", { 2 | design <- get_three_plus_three( 3 | num_doses = 5, 4 | allow_deescalate = TRUE # the 'more common' variant per Korn &al Stat Med (1994) 5 | ) 6 | mtdi_dist <- mtdi_lognormal(CV = 2 7 | ,median = 5 8 | ,units = "mg/kg" 9 | ) 10 | options(dose_levels = c(0.5, 1, 2, 4, 6)) 11 | 12 | set.seed(2020) # avoid gut-wrenching random failures on CRAN 13 | design %>% simulate_trials( 14 | num_sims = 200 15 | , true_prob_tox = mtdi_dist 16 | ) -> SIMS 17 | 18 | options(ordinalizer = function(MTDi, r0 = 1.5) { 19 | MTDi * r0 ^ c(Gr1=-2, Gr2=-1, Gr3=0, Gr4=1, Gr5=2) 20 | }) 21 | 22 | exact(design) %>% simulate_trials(true_prob_tox = mtdi_dist) -> EXACT 23 | 24 | SIMS_safety <- summary(SIMS)$safety 25 | abserrs <- abs(SIMS_safety[1,] - summary(EXACT)$safety) 26 | relerrs <- abserrs / SIMS_safety['MCSE',] 27 | 28 | expect(all(max(relerrs) < 3), 29 | "entries in simulated 3+3 safety table are exact ± 3 MCSEs") 30 | 31 | }) 32 | -------------------------------------------------------------------------------- /tests/testthat/test-fractionation.R: -------------------------------------------------------------------------------- 1 | test_that("CPE-cognizant tox fractionation matches old nested sims", { 2 | 3 | ## Revisit the 3+3 example from Intro vignette 4 | design <- get_three_plus_three(num_doses = 5 5 | ,allow_deescalate = TRUE) 6 | 7 | mtdi_gen <- hyper_mtdi_lognormal(CV = 1 8 | ,median_mtd = 5 9 | ,median_sdlog = 0.5 10 | ,units="mg/kg" 11 | ) 12 | options(dose_levels = c(0.5, 1, 2, 4, 6)) # specify actual dosing 13 | 14 | set.seed(2021) 15 | design %>% simulate_trials( 16 | num_sims = 2000 17 | , true_prob_tox = mtdi_gen # pull tox probs from a MODEL, not thin air 18 | ) -> HYPERSIMS 19 | 20 | tox_threshold_scaling <- function(MTDi, r0) { 21 | MTDi * r0 ^ c(Gr1=-2, Gr2=-1, Gr3=0, Gr4=1, Gr5=2) 22 | } 23 | 24 | r0 <- 2 25 | safety <- summary(HYPERSIMS 26 | ,ordinalizer = tox_threshold_scaling 27 | ,r0 = r0)$safety 28 | 29 | ## ~~ Let's compare results obtained via CPE ~~ 30 | 31 | MTDi_gen <- HyperMTDi_lognormal$new(CV = 1 32 | ,median_mtd = 5 33 | ,median_sdlog = 0.5 34 | ,units = "mg/kg" 35 | ,n = 1000)$doses(getOption("dose_levels")) 36 | 37 | bUF <- MTDi_gen$fractionate(Cpe3_3$new(5) 38 | ,kappa = log(r0) 39 | ) 40 | 41 | ## TODO: A more sophisticated view would not put the two MCSE's on equal footing! 42 | err_se <- (bUF[1,] - safety[1,]) / sqrt(bUF['MCSE',]^2 + safety['MCSE',]^2) 43 | expect_lt(max(abs(err_se)), 3) # expect all differences under 3 sigma 44 | 45 | }) 46 | -------------------------------------------------------------------------------- /tests/testthat/test-viola-dtp.R: -------------------------------------------------------------------------------- 1 | test_that("Crm$trace_paths() yields same VIOLA result as dtpcrm's version", { 2 | ## VIOLA trial set-up 3 | start.dose.level <- 3 4 | target.DLT <- 0.2 5 | 6 | prior.DLT <- c(0.03, 0.07, 0.12, 0.20, 0.30, 0.40, 0.52) 7 | prior.var <- 0.75 8 | 9 | stop_func <- function(x) { 10 | y <- stop_for_excess_toxicity_empiric(x, 11 | tox_lim = target.DLT + 0.1, 12 | prob_cert = 0.72, 13 | dose = 1) 14 | if(y$stop){ 15 | x <- y 16 | } else { 17 | x <- dtpcrm::stop_for_consensus_reached(x, req_at_mtd = 12) 18 | } 19 | } 20 | 21 | crm <- Crm$new(skeleton = prior.DLT, 22 | scale = sqrt(prior.var), 23 | target = target.DLT)$ 24 | stop_func(stop_func)$ 25 | no_skip_esc(TRUE)$ 26 | no_skip_deesc(FALSE)$ 27 | global_coherent_esc(TRUE) 28 | 29 | pmx <- crm$trace_paths(root_dose = start.dose.level, 30 | cohort_sizes = rep(3, 7))$path_matrix() 31 | 32 | data(viola_dtp) # saved for comparison 33 | 34 | ## Of note, the new Crm$paths() method retains more dose-recommendation info 35 | ## than the 'dtpcrm' code under its default settings which write 'NA' dose recs 36 | ## when the trial stops early. 37 | ## Consequently, to effect a test, we copy NA's over from viola_dtp to pmx: 38 | viola_paths <- unique(viola_dtp) 39 | expect_equal(dim(pmx), dim(viola_paths)) 40 | if (all(dim(pmx) == dim(viola_paths))) { 41 | pmx[is.na(viola_paths)] <- NA_integer_ 42 | expect_equal(as.integer(pmx), as.integer(as.matrix(viola_paths))) 43 | } 44 | }) 45 | 46 | test_that("Crm$trace_paths() answer invariant to unroll depth", { 47 | start.dose.level <- 3 48 | target.DLT <- 0.2 49 | 50 | prior.DLT <- c(0.03, 0.07, 0.12, 0.20, 0.30, 0.40, 0.52) 51 | prior.var <- 0.75 52 | 53 | stop_func <- function(x) { 54 | y <- stop_for_excess_toxicity_empiric(x, 55 | tox_lim = target.DLT + 0.1, 56 | prob_cert = 0.72, 57 | dose = 1) 58 | if(y$stop){ 59 | x <- y 60 | } else { 61 | x <- dtpcrm::stop_for_consensus_reached(x, req_at_mtd = 12) 62 | } 63 | } 64 | 65 | crm <- Crm$new(skeleton = prior.DLT, 66 | scale = sqrt(prior.var), 67 | target = target.DLT)$ 68 | stop_func(stop_func)$ 69 | no_skip_esc(TRUE)$ 70 | no_skip_deesc(FALSE)$ 71 | global_coherent_esc(TRUE) 72 | 73 | pmx1 <- crm$trace_paths(root_dose = start.dose.level, 74 | cohort_sizes = rep(3, 7), 75 | unroll = 1)$path_matrix() 76 | 77 | pmx2 <- crm$trace_paths(root_dose = start.dose.level, 78 | cohort_sizes = rep(3, 7), 79 | unroll = 2)$path_matrix() 80 | 81 | pmx3 <- crm$trace_paths(root_dose = start.dose.level, 82 | cohort_sizes = rep(3, 7), 83 | unroll = 3)$path_matrix() 84 | 85 | pmx4 <- crm$trace_paths(root_dose = start.dose.level, 86 | cohort_sizes = rep(3, 7), 87 | unroll = 4)$path_matrix() 88 | 89 | expect_equal(dim(pmx2), dim(pmx1)) 90 | expect_equal(dim(pmx3), dim(pmx1)) 91 | expect_equal(dim(pmx4), dim(pmx1)) 92 | }) 93 | 94 | test_that("Crm-class path_matrix can be recovered from path_array", { 95 | ## VIOLA trial set-up 96 | start.dose.level <- 3 97 | target.DLT <- 0.2 98 | 99 | prior.DLT <- c(0.03, 0.07, 0.12, 0.20, 0.30, 0.40, 0.52) 100 | prior.var <- 0.75 101 | 102 | stop_func <- function(x) { 103 | y <- stop_for_excess_toxicity_empiric(x, 104 | tox_lim = target.DLT + 0.1, 105 | prob_cert = 0.72, 106 | dose = 1) 107 | if(y$stop){ 108 | x <- y 109 | } else { 110 | x <- dtpcrm::stop_for_consensus_reached(x, req_at_mtd = 12) 111 | } 112 | } 113 | 114 | crm <- Crm$new(skeleton = prior.DLT, 115 | scale = sqrt(prior.var), 116 | target = target.DLT)$ 117 | stop_func(stop_func)$ 118 | no_skip_esc(TRUE)$ 119 | no_skip_deesc(FALSE)$ 120 | global_coherent_esc(TRUE) 121 | 122 | crm$trace_paths(root_dose = start.dose.level, 123 | cohort_sizes = rep(3, 7)) 124 | 125 | pmx <- crm$path_matrix() 126 | Tv <- crm$path_array(condense=FALSE) 127 | 128 | doses <- apply(Tv, MARGIN=1:2, FUN=function(x) which(!is.na(x))[1]) 129 | colnames(doses) <- paste0("D",0:6) # force pmx column names 130 | 131 | ## Since pmx may contain final recommendations that were never dosed 132 | ## and consequently have no corresponding toxicity counts, which we 133 | ## can hardly expect to recover from T, we have to mask these cases 134 | ## in order to effect our comparison: 135 | M <- !is.na(doses) 136 | M[M] <- 1L 137 | M[!M] <- NA_integer_ 138 | expect_equal(M*doses, M*pmx[,colnames(doses)]) 139 | 140 | }) 141 | -------------------------------------------------------------------------------- /vignettes/DTP-vs-Korn94.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "DTP-vs-Korn94" 3 | author: "David C. Norris" 4 | date: "12/23/2020" 5 | output: pdf_document 6 | bibliography: precautionary-package.bib 7 | --- 8 | 9 | ```{r setup, include=FALSE} 10 | knitr::opts_chunk$set(echo = TRUE) 11 | ``` 12 | 13 | ```{r seeing-is-believing-1, fig.cap=paste0("Dose transition paths computed by package `escalation` v", packageVersion('escalation'), ", for the trivial 3+3 trial with a single dose, under the `allow_deescalate=TRUE` regime which implements the \"more common\" variant described in @korn_comparison_1994 [p1801], in which the \"requirement is to have 6 patients treated at the MTD (if it is higher than level 0).\" The top, right yellow leaf node of this graph suggests that the case '1NNN' proceeds immediately to declare $MTD=1$ without enrolling a second cohort of 3.")} 14 | library(escalation) 15 | p1 <- get_three_plus_three(num_doses=1, allow_deescalate=TRUE) %>% 16 | get_dose_paths(cohort_sizes=rep(3, 2)) # D=1 trial enrolls at most 2 cohorts 17 | g1 <- graph_paths(p1) 18 | g1$width <- g1$height <- 250 19 | g1 20 | ``` 21 | 22 | \newpage 23 | ```{r seeing-is-believing-2, fig.cap=paste0("Dose transition paths computed by package `escalation` v", packageVersion('escalation'), ", for the 3+3 trial with 2 doses, under the `allow_deescalate=TRUE` regime which implements the \"more common\" variant described in @korn_comparison_1994 [p1801], in which the \"requirement is to have 6 patients treated at the MTD (if it is higher than level 0).\" Paths '1NNN, 2NNN, 2' and '1NNT, 1NNN, 2NNN, 2' appear to declare $MTD=2$ after enrolling only 3 patients at dose level 2.")} 24 | p2 <- get_three_plus_three(num_doses=2, allow_deescalate=TRUE) %>% 25 | get_dose_paths(cohort_sizes=rep(3, 4)) # D=2 trial enrolls at most 4 cohorts 26 | graph_paths(p2) 27 | ``` 28 | 29 | \newpage 30 | # Not just DTP, but the sims themselves omit 2nd MTD cohort 31 | 32 | ```{r sims-themselves} 33 | set.seed(2020) 34 | true_prob_tox <- c(0, 0, 0) # drive simulation to top dose with zero toxicity 35 | num_sims <- 1 36 | sims <- get_three_plus_three(num_doses = 3, allow_deescalate = TRUE) %>% 37 | simulate_trials(num_sims = num_sims, true_prob_tox = true_prob_tox) 38 | sims[[1]][[1]][[1]]$fit 39 | ``` 40 | 41 | # References 42 | --------------------------------------------------------------------------------