GitHub

CRAN_Status_Badge R-CMD-check CRAN Downloads Per Month CRAN Downloads Total

Overview

ShortForm is an R package for constructing short-form assessments from larger item banks using reproducible, optimization-based workflows.

It provides implementations of metaheuristic search algorithms to automate item selection while preserving prespecified psychometric properties. The package is designed for researchers and practitioners who need scalable, transparent, and reproducible methods for reducing assessment length.


Key Features

  • Automated short-form construction from full item banks
  • Multiple optimization algorithms:
    • Ant Colony Optimization (ACO)
    • Tabu Search (TS)
    • Simulated Annealing (SA)
  • Integration with lavaan and Mplus workflows
  • Support for custom objective functions and model specifications
  • Reproducible, scriptable workflows for assessment design

Use Cases

ShortForm is useful when you need to:

  • Reduce assessment length while maintaining measurement validity
  • Automate item selection workflows for large-scale assessments
  • Build reproducilbe pipelines for psychometric modeling and evaluation

Engineering Highlights

This package demonstrates:

  • Development and maintenance of an R package distributed via CRAN
  • Implementation of optimization algorithms for applied statistical workflows
  • Automated build and testing pipelines using CI/CD
  • Integration with other modeling tools
  • Reproducible examples using structured simulated data

This document was created on 2026-08-14.

Installation

install.packages("ShortForm") # the CRAN-approved version
require("devtools")
devtools::install_github("AnthonyRaborn/ShortForm", branch = "devel") # the developmental version

Quick Examples

set.seed(58310)
library(ShortForm)
# Example workflow:
# 1. Define item pool and model
# 2. Run optimization algorithm
# 3. Evaluate resulting short form
result_ACO <- antColony(
    data = simulated_test_data,
    initialModel = exampleAntModel,
    itemsPerFactor = 15,
    steps = 100,
    fit.indices = c("cfi", "rmsea"),
    fit.statistics.test = "(cfi > 0.98)&(rmsea < 0.03)",
    maxIterations = 200
)
##   Run number 1 and ant number 1.            Run number 1 and ant number 2.            Run number 1 and ant number 3.            Run number 1 and ant number 4.            Run number 1 and ant number 5.            Run number 1 and ant number 6.            Run number 1 and ant number 7.            Run number 1 and ant number 8.            Run number 1 and ant number 9.            Run number 1 and ant number 10.            Run number 1 and ant number 11.            Run number 1 and ant number 12.            Run number 1 and ant number 13.            Run number 1 and ant number 14.            Run number 1 and ant number 15.            Run number 1 and ant number 16.            Run number 1 and ant number 17.            Run number 1 and ant number 18.            Run number 1 and ant number 19.            Run number 1 and ant number 20.            Run number 2 and ant number 1.            Run number 2 and ant number 2.            Run number 2 and ant number 3.            Run number 2 and ant number 4.            Run number 2 and ant number 5.            Run number 2 and ant number 6.            Run number 2 and ant number 7.            Run number 2 and ant number 8.            Run number 2 and ant number 9.            Run number 2 and ant number 10.            Run number 2 and ant number 11.            Run number 2 and ant number 12.            Run number 2 and ant number 13.            Run number 2 and ant number 14.            Run number 2 and ant number 15.            Run number 2 and ant number 16.            Run number 2 and ant number 17.            Run number 2 and ant number 18.            Run number 2 and ant number 19.            Run number 2 and ant number 20.            Run number 3 and ant number 1.            Run number 3 and ant number 2.            Run number 3 and ant number 3.            Run number 3 and ant number 4.            Run number 3 and ant number 5.            Run number 3 and ant number 6.            Run number 3 and ant number 7.            Run number 3 and ant number 8.            Run number 3 and ant number 9.            Run number 3 and ant number 10.            Run number 3 and ant number 11.            Run number 3 and ant number 12.            Run number 3 and ant number 13.            Run number 3 and ant number 14.            Run number 3 and ant number 15.            Run number 3 and ant number 16.            Run number 3 and ant number 17.            Run number 3 and ant number 18.            Run number 3 and ant number 19.            Run number 3 and ant number 20.            Run number 4 and ant number 1.            Run number 4 and ant number 2.            Run number 4 and ant number 3.            Run number 4 and ant number 4.            Run number 4 and ant number 5.            Run number 4 and ant number 6.            Run number 4 and ant number 7.            Run number 4 and ant number 8.            Run number 4 and ant number 9.            Run number 4 and ant number 10.            Run number 4 and ant number 11.            Run number 4 and ant number 12.            Run number 4 and ant number 13.            Run number 4 and ant number 14.            Run number 4 and ant number 15.            Run number 4 and ant number 16.            Run number 4 and ant number 17.            Run number 4 and ant number 18.            Run number 4 and ant number 19.            Run number 4 and ant number 20.            Run number 5 and ant number 1.            Run number 5 and ant number 2.            Run number 5 and ant number 3.            Run number 5 and ant number 4.            Run number 5 and ant number 5.            Run number 5 and ant number 6.            Run number 5 and ant number 7.            Run number 5 and ant number 8.            Run number 5 and ant number 9.            Run number 5 and ant number 10.            Run number 5 and ant number 11.            Run number 5 and ant number 12.            Run number 5 and ant number 13.            Run number 5 and ant number 14.            Run number 5 and ant number 15.            Run number 5 and ant number 16.            Run number 5 and ant number 17.            Run number 5 and ant number 18.            Run number 5 and ant number 19.            Run number 5 and ant number 20.            Run number 6 and ant number 1.            Run number 6 and ant number 2.            Run number 6 and ant number 3.            Run number 6 and ant number 4.            Run number 6 and ant number 5.            Run number 6 and ant number 6.            Run number 6 and ant number 7.            Run number 6 and ant number 8.            Run number 6 and ant number 9.            Run number 6 and ant number 10.            Run number 6 and ant number 11.            Run number 6 and ant number 12.            Run number 6 and ant number 13.            Run number 6 and ant number 14.            Run number 6 and ant number 15.            Run number 6 and ant number 16.            Run number 6 and ant number 17.            Run number 6 and ant number 18.            Run number 6 and ant number 19.            Run number 6 and ant number 20.            Run number 7 and ant number 1.            Run number 7 and ant number 2.            Run number 7 and ant number 3.            Run number 7 and ant number 4.            Run number 7 and ant number 5.            Run number 7 and ant number 6.            Run number 7 and ant number 7.            Run number 7 and ant number 8.            Run number 7 and ant number 9.            Run number 7 and ant number 10.            Run number 7 and ant number 11.            Run number 7 and ant number 12.            Run number 7 and ant number 13.            Run number 7 and ant number 14.            Run number 7 and ant number 15.            Run number 7 and ant number 16.            Run number 7 and ant number 17.            Run number 7 and ant number 18.            Run number 7 and ant number 19.            Run number 7 and ant number 20.            Run number 8 and ant number 1.            Run number 8 and ant number 2.            Run number 8 and ant number 3.            Run number 8 and ant number 4.            Run number 8 and ant number 5.            Run number 8 and ant number 6.            Run number 8 and ant number 7.            Run number 8 and ant number 8.            Run number 8 and ant number 9.            Run number 8 and ant number 10.            Run number 8 and ant number 11.            Run number 8 and ant number 12.            Run number 8 and ant number 13.            Run number 8 and ant number 14.            Run number 8 and ant number 15.            Run number 8 and ant number 16.            Run number 8 and ant number 17.            Run number 8 and ant number 18.            Run number 8 and ant number 19.            Run number 8 and ant number 20.            Run number 9 and ant number 1.            Run number 9 and ant number 2.            Run number 9 and ant number 3.            Run number 9 and ant number 4.            Run number 9 and ant number 5.            Run number 9 and ant number 6.            Run number 9 and ant number 7.            Run number 9 and ant number 8.            Run number 9 and ant number 9.            Run number 9 and ant number 10.            Run number 9 and ant number 11.            Run number 9 and ant number 12.            Run number 9 and ant number 13.            Run number 9 and ant number 14.            Run number 9 and ant number 15.            Run number 9 and ant number 16.            Run number 9 and ant number 17.            Run number 9 and ant number 18.            Run number 9 and ant number 19.            Run number 9 and ant number 20.            Run number 10 and ant number 1.            Run number 10 and ant number 2.            Run number 10 and ant number 3.            Run number 10 and ant number 4.            Run number 10 and ant number 5.            Run number 10 and ant number 6.            Run number 10 and ant number 7.            Run number 10 and ant number 8.            Run number 10 and ant number 9.            Run number 10 and ant number 10.            Run number 10 and ant number 11.            Run number 10 and ant number 12.            Run number 10 and ant number 13.            Run number 10 and ant number 14.            Run number 10 and ant number 15.            Run number 10 and ant number 16.            Run number 10 and ant number 17.            Run number 10 and ant number 18.            Run number 10 and ant number 19.            Run number 10 and ant number 20.            Run number 11 and ant number 1.            Run number 11 and ant number 2.            Run number 11 and ant number 3.            Run number 11 and ant number 4.            Run number 11 and ant number 5.            Run number 11 and ant number 6.            Run number 11 and ant number 7.            Run number 11 and ant number 8.            Run number 11 and ant number 9.            Run number 11 and ant number 10.            Run number 11 and ant number 11.            Run number 11 and ant number 12.            Run number 11 and ant number 13.            Run number 11 and ant number 14.            Run number 11 and ant number 15.            Run number 11 and ant number 16.            Run number 11 and ant number 17.            Run number 11 and ant number 18.            Run number 11 and ant number 19.            Run number 11 and ant number 20.            Run number 12 and ant number 1.            Run number 12 and ant number 2.            Run number 12 and ant number 3.            Run number 12 and ant number 4.            Run number 12 and ant number 5.            Run number 12 and ant number 6.            Run number 12 and ant number 7.            Run number 12 and ant number 8.            Run number 12 and ant number 9.            Run number 12 and ant number 10.            Run number 12 and ant number 11.            Run number 12 and ant number 12.            Run number 12 and ant number 13.            Run number 12 and ant number 14.            Run number 12 and ant number 15.            Run number 12 and ant number 16.            Run number 12 and ant number 17.            Run number 12 and ant number 18.            Run number 12 and ant number 19.            Run number 12 and ant number 20.            Run number 13 and ant number 1.            Run number 13 and ant number 2.            Run number 13 and ant number 3.            Run number 13 and ant number 4.            Run number 13 and ant number 5.            Run number 13 and ant number 6.            Run number 13 and ant number 7.            Run number 13 and ant number 8.            Run number 13 and ant number 9.            Run number 13 and ant number 10.            Run number 13 and ant number 11.            Run number 13 and ant number 12.            Run number 13 and ant number 13.            Run number 13 and ant number 14.            Run number 13 and ant number 15.            Run number 13 and ant number 16.            Run number 13 and ant number 17.            Run number 13 and ant number 18.            Run number 13 and ant number 19.            Run number 13 and ant number 20.            Run number 14 and ant number 1.            Run number 14 and ant number 2.            Run number 14 and ant number 3.            Run number 14 and ant number 4.            Run number 14 and ant number 5.            Run number 14 and ant number 6.            Run number 14 and ant number 7.            Run number 14 and ant number 8.            Run number 14 and ant number 9.            Run number 14 and ant number 10.            Run number 14 and ant number 11.            Run number 14 and ant number 12.            Run number 14 and ant number 13.            Run number 14 and ant number 14.            Run number 14 and ant number 15.            Run number 14 and ant number 16.            Run number 14 and ant number 17.            Run number 14 and ant number 18.            Run number 14 and ant number 19.            Run number 14 and ant number 20.            Run number 15 and ant number 1.            Run number 15 and ant number 2.            Run number 15 and ant number 3.            Run number 15 and ant number 4.            Run number 15 and ant number 5.            Run number 15 and ant number 6.            Run number 15 and ant number 7.            Run number 15 and ant number 8.            Run number 15 and ant number 9.            Run number 15 and ant number 10.            Run number 15 and ant number 11.            Run number 15 and ant number 12.            Run number 15 and ant number 13.            Run number 15 and ant number 14.            Run number 15 and ant number 15.            Run number 15 and ant number 16.            Run number 15 and ant number 17.            Run number 15 and ant number 18.            Run number 15 and ant number 19.            Run number 15 and ant number 20.            Run number 16 and ant number 1.            Run number 16 and ant number 2.            Run number 16 and ant number 3.            Run number 16 and ant number 4.            Run number 16 and ant number 5.            Run number 16 and ant number 6.            Run number 16 and ant number 7.            Run number 16 and ant number 8.            Run number 16 and ant number 9.            Run number 16 and ant number 10.            Run number 16 and ant number 11.            Run number 16 and ant number 12.            Run number 16 and ant number 13.            Run number 16 and ant number 14.            Run number 16 and ant number 15.            Run number 16 and ant number 16.            Run number 16 and ant number 17.            Run number 16 and ant number 18.            Run number 16 and ant number 19.            Run number 16 and ant number 20.            Run number 17 and ant number 1.            Run number 17 and ant number 2.            Run number 17 and ant number 3.            Run number 17 and ant number 4.            Run number 17 and ant number 5.            Run number 17 and ant number 6.            Run number 17 and ant number 7.            Run number 17 and ant number 8.            Run number 17 and ant number 9.            Run number 17 and ant number 10.            Run number 17 and ant number 11.            Run number 17 and ant number 12.            Run number 17 and ant number 13.            Run number 17 and ant number 14.            Run number 17 and ant number 15.            Run number 17 and ant number 16.            Run number 17 and ant number 17.            Run number 17 and ant number 18.            Run number 17 and ant number 19.            Run number 17 and ant number 20.            Run number 18 and ant number 1.            Run number 18 and ant number 2.            Run number 18 and ant number 3.            Run number 18 and ant number 4.            Run number 18 and ant number 5.            Run number 18 and ant number 6.            Run number 18 and ant number 7.            Run number 18 and ant number 8.            Run number 18 and ant number 9.            Run number 18 and ant number 10.            Run number 18 and ant number 11.            Run number 18 and ant number 12.            Run number 18 and ant number 13.            Run number 18 and ant number 14.            Run number 18 and ant number 15.            Run number 18 and ant number 16.            Run number 18 and ant number 17.            Run number 18 and ant number 18.            Run number 18 and ant number 19.            Run number 18 and ant number 20.            Run number 19 and ant number 1.            Run number 19 and ant number 2.            Run number 19 and ant number 3.            Run number 19 and ant number 4.            Run number 19 and ant number 5.            Run number 19 and ant number 6.            Run number 19 and ant number 7.            Run number 19 and ant number 8.            Run number 19 and ant number 9.            Run number 19 and ant number 10.            Run number 19 and ant number 11.            Run number 19 and ant number 12.            Run number 19 and ant number 13.            Run number 19 and ant number 14.            Run number 19 and ant number 15.            Run number 19 and ant number 16.            Run number 19 and ant number 17.            Run number 19 and ant number 18.            Run number 19 and ant number 19.            Run number 19 and ant number 20.            Run number 20 and ant number 1.            Run number 20 and ant number 2.            Run number 20 and ant number 3.            Run number 20 and ant number 4.            Run number 20 and ant number 5.            Run number 20 and ant number 6.            Run number 20 and ant number 7.            Run number 20 and ant number 8.            Run number 20 and ant number 9.            Run number 20 and ant number 10.            Run number 20 and ant number 11.            Run number 20 and ant number 12.            Run number 20 and ant number 13.            Run number 20 and ant number 14.            Run number 20 and ant number 15.            Run number 20 and ant number 16.            Run number 20 and ant number 17.            Run number 20 and ant number 18.            Run number 20 and ant number 19.            Run number 20 and ant number 20.            Run number 21 and ant number 1.            Run number 21 and ant number 2.            Run number 21 and ant number 3.            Run number 21 and ant number 4.            Run number 21 and ant number 5.            Run number 21 and ant number 6.            Run number 21 and ant number 7.            Run number 21 and ant number 8.            Run number 21 and ant number 9.            Run number 21 and ant number 10.            Run number 21 and ant number 11.            Run number 21 and ant number 12.            Run number 21 and ant number 13.            Run number 21 and ant number 14.            Run number 21 and ant number 15.            Run number 21 and ant number 16.            Run number 21 and ant number 17.            Run number 21 and ant number 18.            Run number 21 and ant number 19.            Run number 21 and ant number 20.            Run number 22 and ant number 1.            Run number 22 and ant number 2.            Run number 22 and ant number 3.            Run number 22 and ant number 4.            Run number 22 and ant number 5.            Run number 22 and ant number 6.            Run number 22 and ant number 7.            Run number 22 and ant number 8.            Run number 22 and ant number 9.            Run number 22 and ant number 10.            Run number 22 and ant number 11.            Run number 22 and ant number 12.            Run number 22 and ant number 13.            Run number 22 and ant number 14.            Run number 22 and ant number 15.            Run number 22 and ant number 16.            Run number 22 and ant number 17.            Run number 22 and ant number 18.            Run number 22 and ant number 19.            Run number 22 and ant number 20.            Run number 23 and ant number 1.            Run number 23 and ant number 2.            Run number 23 and ant number 3.            Run number 23 and ant number 4.            Run number 23 and ant number 5.            Run number 23 and ant number 6.            Run number 23 and ant number 7.            Run number 23 and ant number 8.            Run number 23 and ant number 9.            Run number 23 and ant number 10.            Run number 23 and ant number 11.            Run number 23 and ant number 12.            Run number 23 and ant number 13.            Run number 23 and ant number 14.            Run number 23 and ant number 15.            Run number 23 and ant number 16.            Run number 23 and ant number 17.            Run number 23 and ant number 18.            Run number 23 and ant number 19.            Run number 23 and ant number 20.            Run number 24 and ant number 1.            Run number 24 and ant number 2.            Run number 24 and ant number 3.            Run number 24 and ant number 4.            Run number 24 and ant number 5.            Run number 24 and ant number 6.            Run number 24 and ant number 7.            Run number 24 and ant number 8.            Run number 24 and ant number 9.            Run number 24 and ant number 10.            Run number 24 and ant number 11.            Run number 24 and ant number 12.            Run number 24 and ant number 13.            Run number 24 and ant number 14.            Run number 24 and ant number 15.            Run number 24 and ant number 16.            Run number 24 and ant number 17.            Run number 24 and ant number 18.            Run number 24 and ant number 19.            Run number 24 and ant number 20.           [1] "Compiling results."
summary(result_ACO)
##  Algorithm: Ant Colony Optimization
##  Total Run Time: 3.973 secs
##  
##  lavaan 0.7-2 ended normally after 59 iterations
##  
##    Estimator                                         ML
##    Optimization method                           NLMINB
##    Number of model parameters                        48
##  
##    Number of observations                          1000
##  
##  Model Test User Model:
##                                                        
##    Test statistic                               123.385
##    Degrees of freedom                               104
##    P-value (Chi-square)                           0.094
##  
##  
##  Final Model Syntax:
##  Ability =~ Item15 + Item16 + Item19 + Item2 + Item20 + Item30 + Item31 + Item37
##    + Item4 + Item42 + Item45 + Item50 + Item53 + Item54 + Item55
##  Outcome ~ Ability
##  
##  Fit Indices: cfi, rmsea
##  Fit Test: (cfi > 0.98)&(rmsea < 0.03)
##  Final Model Values: cfi = 0.991, rmsea = 0.014
plot(result_ACO)

set.seed(58310)
result_SA <- simulatedAnnealing(
  initialModel = paste("Ability =~", paste0("Item", 1:56, collapse = " + ")),
  originalData = simulated_test_data,
  maxIterations = 20,
  itemsPerFactor = 40,
  items = paste0("Item", 1:56),
  setChains = 4
)
##  Initializing short form creation.
##  The initial short form is:
##  Ability =~ Item10 + Item43 + Item35 + Item31 + Item42 + Item49 + Item48 + Item20 + Item32 + Item18 + Item36 + Item34 + Item45 + Item50 + Item3 + Item54 + Item2 + Item44 + Item24 + Item7 + Item22 + Item46 + Item53 + Item13 + Item39 + Item38 + Item51 + Item21 + Item15 + Item56 + Item8 + Item29 + Item40 + Item26 + Item23 + Item47 + Item1 + Item52 + Item27 + Item9
##  
##  Using the short form randomNeighbor function.
##  Finished initializing short form options.
##   Current Progress: 
##  Chain number 1 complete. 
##  Chain number 2 complete. 
##  Chain number 3 complete. 
##  Chain number 4 complete.
summary(result_SA)
##  Algorithm: Simulated Annealing
##  Total Run Time: 2.059 secs
##  
##  lavaan 0.7-2 ended normally after 34 iterations
##  
##    Estimator                                         ML
##    Optimization method                           NLMINB
##    Number of model parameters                       120
##  
##    Number of observations                          1000
##  
##  Model Test User Model:
##                                                        
##    Test statistic                               789.761
##    Degrees of freedom                               740
##    P-value (Chi-square)                           0.100
##  
##  
##  Final Model Syntax:
##  Ability =~ Item10 + Item43 + Item35 + Item31 + Item42 + Item49 + Item48 + Item20
##    + Item32 + Item18 + Item28 + Item34 + Item45 + Item50 + Item3 + Item25 +
##    Item2 + Item44 + Item24 + Item7 + Item22 + Item46 + Item53 + Item13 + Item39 +
##    Item38 + Item51 + Item21 + Item15 + Item56 + Item8 + Item29 + Item40 + Item26
##    + Item23 + Item47 + Item19 + Item52 + Item27 + Item9
##  
##  Criterion: "cfi" (maximized)
##  Final Model Value: 0.989
plot(result_SA)

set.seed(58310)
shortAntModel <- "
Ability =~ Item1 + Item2 + Item3 + Item4 + Item5 + Item6 + Item7 + Item8
Ability ~ Outcome
"
result_TS <- tabuSearch(
  initialModel = shortAntModel,
  originalData = simulated_test_data, itemsPerFactor = 7,
  maxIterations = 10, tabu.size = 3, parallel = FALSE
)
##  Running iteration 1 of 10.   Running iteration 2 of 10.   Running iteration 3 of 10.   Running iteration 4 of 10.   Running iteration 5 of 10.   Running iteration 6 of 10.   Running iteration 7 of 10.   Running iteration 8 of 10.   Running iteration 9 of 10.   Running iteration 10 of 10.
summary(result_TS)
##  Algorithm: Tabu Search
##  Total Run Time: 1.497 secs
##  
##  lavaan 0.7-2 ended normally after 36 iterations
##  
##    Estimator                                         ML
##    Optimization method                           NLMINB
##    Number of model parameters                        22
##  
##    Number of observations                          1000
##  
##  Model Test User Model:
##                                                        
##    Test statistic                                18.858
##    Degrees of freedom                                20
##    P-value (Chi-square)                           0.531
##  
##  
##  Final Model Syntax:
##  Ability =~ Item1 + Item6 + Item3 + Item4 + Item5 + Item7 + Item8
##  Ability ~ Outcome
##  
##  Criterion: "cfi" (maximized)
##  Final Model Value: 1
plot(result_TS)

Workflow

flowchart LR
    A@{ shape: lean-r, label: "Full Item Bank" } --> B[Specify Model]
    B --> C[Run Optimization Algorithm]
    C --> D[Evaluate Candidate Forms]
    D --> |One or More Forms Fit| E@{ shape: diamond, label: "Select Short Form" }
    D --> |No Adequate Forms Found| C
    E --> F@{ shape: lean-l, label: "Reporting & Visualization" }
Loading

Outputs

ShortForm produces diagnostic outputs such as:

  • Objective function convergence plots
  • Algorithm-specific diagnostics
  • Summary statistics for selected item sets

Algorithms

Ant Colony Optimization (ACO)

Implementation adapted from Leite, Huang, & Marcoulides (2008).

Tabu Search (TS)

Based on Marcoulides & Falk (2018), extended for model search and short-form construction.

Simulated Annealing (SA)

Provides one of the first implementations of simulated annealing for psychometric model selection workflows. Implemented following Kirkpatrick et al. (1983).


Performance Notes

Computational time depends on:

  • Number and types of items
  • Dimensionality/model complexity
  • Algorithm convergence settings

Parallelization is supported for certain workflows.


Reproducibility

ShortForm is designed for reproducible analytical workflows:

  • Fully scriptable
  • Compatible with R Markdown and Quarto
  • Supports integration into larger modeling pipelines

Reproducible Docker Environment

This repository includes a Dockerfile for building and checking the package in a clean R environment.

docker build -t shortform-r .

The Docker build installs package dependencies, builds the package source tarball, and runs R CMD check on the built package. This provides an additional reproducibility check alongside the GitHub Actions CI workflow.


License

LGPL (>= 2.0, < 3) | Mozilla Public License


Citation

If you use this package, please cite:

Raborn A, Leite W (2024). ShortForm: Automatic Short Form Creation. doi:10.32614/CRAN.package. ShortForm https://doi.org/10.32614/CRAN.package.ShortForm, R package version 0.5.6, https://CRAN.R-project.org/package=ShortForm.

Read the original on github.com ↗