knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.path = "man/figures/README-",
  out.width = "100%"
)

account

Lifecycle: experimental R-CMD-check

Bayesian demographic accounts

The package is still under development, and the interface will change.

The package uses modified versions of code from packages skellam and extraDistn.

Inputs

rates

A named list of data frames, holding estimated birth rates, death rates, and migration rates.

The data frame with birth rates must be named "births" and the data frame with death rates must be named "deaths". In a model without regions, the data frames with migration rates can have names

"immigration", "emigration"

or

"immigration1", "emigration1", "immigration2", "emigration2"

In a model with regions, the data frames with migration rates can have names

"immigration", "emigration", "internal_in", "internal_out"

or

"immigration1", "emigration1", "immigration2", "emigration2", "internal_in", "internal_out"

Each data frame has the following variables:

| Variable | Births | Deaths | Migration | |:-------------------|:----------:|:----------:|:----------:| | "age" | yes | yes | yes | | "cohort" | no | no | no | | "sex"/"gender" | no | yes | yes | | "time" | yes | yes | yes | | "region" | sometimes | sometimes | sometimes | | "rate" | yes | yes | yes | Used if, and only if, rates includes series "internal_in" and "internal_out".

Validity checks (checking function)

data_models

A list of objects of class "datamodel". Each data model has contains the name of a demographic series and the name of a dataset. The only restrictions on the names of datasets is that they cannot be blank or NA, and must be unique to each data model. There must be one, and only one, data model for demographic series "births", and that data model must have class "dm_exact". Similarly, there be one data model "deaths", with class "dm_exact". Aside from births and deaths, in a model without regions, the permitted values for demographic series are

"population", "immigration", "emigration"

or

"population", "immigration1", "emigration1", "immigration2", "emigration2"

In a model with regions, the permitted values for demographic series are

"population", "immigration", "emigration", "internal_in", "internal_out"

or

"population", "immigration1", "emigration1", "immigration2", "emigration2", "internal_in", "internal_out"

Datasets have the following variables:

| Variable | Population | Births | Deaths | Migration | |:-------------------|:----------:|:----------:|:----------:|:----------:| | "age" | yes | yes | yes | yes | | "cohort" | no | yes | yes | yes | | "sex"/"gender" | yes | no | yes | yes | | "time" | yes | yes | yes | yes | | "region" | sometimes | sometimes | sometimes | sometimes | | "count" | yes | yes | yes | yes | *Required if there are data models for "internal_in" and "internal_out".

Checks

account

A named list of data frames, holding estimated population, birth, death, and migration counts.

The data frame with population counts is named "population", the data frame with birth counts is named "births", and the data frame with death counts is named "deaths". In a model without regions, the data frames with migration counts have names

"immigration", "emigration"

or

"immigration1", "emigration1", "immigration2", "emigration2"

In a model with regions, the data frames with migration counts have names

"immigration", "emigration", "internal_in", "internal_out"

or

"immigration1", "emigration1", "immigration2", "emigration2", "internal_in", "internal_out"

| Variable | Births | Deaths | Migration | |:-------------------|:----------:|:----------:|:----------:| | "age" | yes | yes | yes | | "cohort" | yes | yes | yes | | "sex"/"gender" | yes | yes | yes | | "time" | yes | yes | yes | | "region" | sometimes | sometimes | sometimes | | "count" | yes | yes | yes | Used if and only if account includes series "internal_in" and "internal_out".

Checks

C++ functions

The following diagram lists all C++ functions in the package. Each function is called by the one immediately above it in the tree structure.

None of these functions are visible to end users.

S = stub
W = written, but not yet ready to translate
R = ready to translate
T = translated
* = included earlier
C$f = method f for R6 class C
f.C = method f for S3 class C

W use_pfilters
-------------------- NoReg --------------------
W     PFilterNoReg$initialize
W         PFilter$initialize
R         new_cdms_noreg
R             new_cdm_noreg_poibin  
W     PFilter$run
W         PFilterNoReg$draw_proposal_init
R             draw_counts_true.cdms_noreg
R                 fill_counts_true.cdm_noreg_poibin
T                     rpoibin1
W         PFilterNoReg$calc_loglik_init
R             calc_loglik.cdms_noreg
R                 calc_loglik.cdm_noreg_poibin
T                     dpoibin1
W         PFilterNoReg$calc_logratio_init
R             calc_logimp.cdms_noreg
R                 fill_logimp.cdm_noreg_poibin
W         PFilter$calc_wt
S         PFilter$resample
W         PFilterNoReg$draw_proposal
*             draw_counts_true.cdms_noreg
*                 fill_counts_true.cdm_noreg_poibin
*                     rpoibin1
W             rskeltr
W                 rskeltr1
R                     pskel1
R                     qskel1
T             rpoistr
T                rpoistr1
W         PFilterNoReg$calc_loglik
*             calc_loglik.cdms_noreg
*                 calc_loglik.cdm_noreg_poibin
W         PFilterNoReg$calc_logratio
*             calc_logimp.cdms_noreg
*                 fill_logimp.cdm_noreg_poibin
W             dskeltr1
R                 dskel1
*                 pskel1
*             pskel1
*         PFilter$calc_wt
*         PFilter$resample
S     PFilterNoReg$make_output
------------------- WithReg -------------------
W     PFilterWithReg$initialize   
*         PFilter$initialize
W         new_cdms_withreg
W             new_cdm_withreg_poibin
*     PFilter$run
W         PFilterWithReg$draw_proposal_init
R             draw_counts_true.cdms_withreg
R                 fill_counts_true.cdm_withreg_poibin
*                     rpoibin1
*         PFilter$calc_wt_init
W             PFilterWithReg$calc_loglik_init
R                 calc_loglik.cdms_withreg
R                     calc_loglik.cdm_withreg_poibin
*                         dpoibin1
W             PFilterWithReg$calc_logimp_init
R                 calc_logimp.cdms_withreg
R                     fill_logimp.cdm_withreg_poibin
*                         dpoibin1
W         PFilterWithReg$draw_proposal
*             draw_counts_true.cdms_withreg
*                 fill_counts_true.cdm_withreg_poibin
*                     rpoibin1
*             rskeltr
*                 rskeltr1
*                     pskel1
*                     qskel1
*             rpoistr
*                 rpoistr1
*         PFilter$calc_wt
W             PFilterWithReg$calc_loglik
*                 calc_loglik.cdms_withreg
*                     calc_loglik.cdm_withreg_poibin
S             PFilterWithReg$calc_logratio
*         PFilter$resample
S     PFilterWithReg$make_output

Workflows for translating from R to C++

New R function

1. R programmer writes original R function

The R programmer writes the function and gives it the name that it will eventually have.

add1 <- function(x) x + 1

2. R programmer writes tests

The R programmer writes standard unit tests.

test_that("'add1' works correctly with valid inputs", {
  expect_equal(add1(10), 11)
})

The R programmer also writes a special unit test that includes the original R function, renamed to have an '_r' suffix. Since the unit-test function and the original function are identical other than the name, the test should pass.

test_that("R and C versions of 'add1' give identical results", {
  add1_r <- function(x) x + 1
  ans_c <- sapply(1:10, add1)
  ans_r <- sapply(1:10, add1_r)
  expect_identical(ans_c, ans_r)
})

3. R programmer notifies C++ programmer

The R programmer adds a READY_TO_TRANSLATE flag to the R function.

## READY_TO_TRANSLATE
add1 <- function(x) x + 1

The R programmer then notifies the C++ programmer (eg via Slack) that the programmer can start the translation.

4. C++ programmer writes C++ version of function

The C++ programmer creates a pull request.

The C++ programmer adds a _r suffix to the original R function.

## READY_TO_TRANSLATE
add1_r <- function(x) x + 1

The C++ programmer writes a C++ version of the R function, and gives the C version the same name as the original R function. {c, eval = FALSE} // [[Rcpp::export]] double add1(double x) return x + 1

The C++ programmer copies over any substantive comments that were attached to the original R function, except for comments describing the type or length of variables which are superceded by C++ declarations.

If the original function is in file R/<filename>.R, then the translated function should be in file src/<filename>.cpp.

The C++ programmer runs the tests. These tests should now use the C++ version of the function. The special 'R vs C test' should compare the results from the C++ version with those from the original R version.

5. R programmer checks the results

Once all the tests are passing, the C++ programmer notifies the R++. The R programmer takes a look at the changes and (all going well) accepts the pull request. The R++ programmer deletes the original R function, plus any associated comments or flags. (Note that the original R function is preserved on GitHub.)

Modifying an existing R function



ONSdigital/Bayesian-demographic-accounts documentation built on Jan. 10, 2022, 12:34 a.m.