Header menu logo bristlecone

Bristlecone

Bristlecone is a library for conducting model-fitting and model-selection analyses on time-series data. Although originally designed for the investigation of non-linear dynamics within ecological and environmental sciences, the library can be used across finance, econometrics and other fields that apply non-linear modelling techniques.

Quick Start

Bristlecone is an F# .NET library. You can easily get started by installing the latest .NET SDK. You may then simply use the Bristlecone package in a script, application, or library. The nuget package is available here.

To use in an F# script

img/example.png

Example

This example demonstrates the layout of a model when defined in Bristlecone.

open Bristlecone            // Opens Bristlecone core library and estimation engine
open Bristlecone.Language   // Open the language for writing Bristlecone models

let hypothesis =

    let vonBertalanffy = 
        Parameter "η" * This ** Parameter "β" - Parameter "κ" * This

    Model.empty
    |> Model.addEquation       "mass"   vonBertalanffy
    |> Model.estimateParameter "η"      noConstraints 0.50 1.50 
    |> Model.estimateParameter "β"      noConstraints 0.01 1.00
    |> Model.estimateParameter "κ"      noConstraints 0.01 1.00 
    |> Model.useLikelihoodFunction (ModelLibrary.Likelihood.sumOfSquares [ "mass" ])
    |> Model.compile

let engine = 
    Bristlecone.mkContinuous
    |> Bristlecone.withCustomOptimisation (Optimisation.Amoeba.swarm 5 20 Optimisation.Amoeba.Solver.Default)

let testSettings = Bristlecone.Test.TestSettings<float>.Default
let testResult = Bristlecone.testModel engine testSettings hypothesis
val hypothesis: Bristlecone.ModelSystem.ModelSystem =
  { Parameters =
     Pool
       (map
          [(ShortCode "β",
            Parameter (Unconstrained, Transform, NotEstimated (0.01, 1.0)));
           (ShortCode "η",
            Parameter (Unconstrained, Transform, NotEstimated (0.5, 1.5)));
           (ShortCode "κ",
            Parameter (Unconstrained, Transform, NotEstimated (0.01, 1.0)))])
    Equations = map [(ShortCode "mass", <fun:Invoke@3682-2>)]
    Measures = map []
    Likelihood = <fun:hypothesis@14> }
val engine: Bristlecone.EstimationEngine.EstimationEngine<float,float> =
  { TimeHandling = Continuous <fun:mkContinuous@23>
    OptimiseWith = InTransformedSpace <fun:swarm@1458>
    Conditioning = RepeatFirstDataPoint
    LogTo = <fun:logger@45-5>
    Random = MathNet.Numerics.Random.MersenneTwister }
val testSettings: Bristlecone.Test.TestSettings<float> =
  { TimeSeriesLength = 30
    StartValues = map []
    EndCondition = <fun:get_Default@78-3>
    GenerationRules = []
    NoiseGeneration = <fun:get_Default@80-4>
    EnvironmentalData = map []
    Resolution = Years PositiveInt 1
    Random = MathNet.Numerics.Random.MersenneTwister
    StartDate = 1/1/1970 12:00:00 AM
    Attempts = 50000 }
val testResult: Result<Bristlecone.Test.TestResult,string> =
  Error
    "You must specify a start point for the following equations: ["+[17 chars]

In the above snippet, a von Bertalanffy growth model is defined as a hypothesis to test. We then create an EstimationEngine, which defines the methodology for model-fitting. In Bristlecone, an EstimationEngine is created and customised using the F# forward pipe operator (for R users this may be familiar; this concept was adapted into the dplyr %>% operator). The call to testModel generates random test data, and assesses whether the model-fitting method can accurately estimate known parameters.

Samples & documentation

An API reference is automatically generated from XML comments in the library implementation.

In addition, this documentation includes step-by-step example analyses. Each analysis may be downloaded as an F# script or Jupyter notebook using the buttons at the top of each example page.

Contributing and copyright

The project is hosted on GitHub where you can report issues, fork the project and submit pull requests. If you're adding a new public API, please also consider adding samples that can be turned into a documentation. You might also want to read the library design notes to understand how it works.

The library is available under an MIT license, which allows modification and redistribution for both commercial and non-commercial purposes. For more information see the License file in the GitHub repository.

Multiple items
module Bristlecone from Bristlecone

--------------------
namespace Bristlecone
module Language from Bristlecone
<summary> An F# Domain Specific Language (DSL) for scripting with Bristlecone. </summary>
val hypothesis: ModelSystem.ModelSystem
val vonBertalanffy: ModelExpression
Multiple items
union case ModelExpression.Parameter: string -> ModelExpression

--------------------
module Parameter from Bristlecone
union case ModelExpression.This: ModelExpression
module Model from Bristlecone.Language
<summary> Terms for scaffolding a model system for use with Bristlecone. </summary>
val empty: ModelBuilder.ModelBuilder
val addEquation: name: string -> eq: ModelExpression -> builder: ModelBuilder.ModelBuilder -> ModelBuilder.ModelBuilder
val estimateParameter: name: string -> constraintMode: Parameter.Constraint -> lower: float -> upper: float -> builder: ModelBuilder.ModelBuilder -> ModelBuilder.ModelBuilder
val noConstraints: Parameter.Constraint
val useLikelihoodFunction: likelihoodFn: ModelSystem.LikelihoodFn -> builder: ModelBuilder.ModelBuilder -> ModelBuilder.ModelBuilder
namespace Bristlecone.ModelLibrary
module Likelihood from Bristlecone.ModelLibrary
<summary>Likelihood functions to represent a variety of distributions and data types.</summary>
<namespacedoc><summary>Pre-built model parts for use in Bristlecone</summary></namespacedoc>
val sumOfSquares: keys: string list -> ModelSystem.ParameterValueAccessor -> data: CodedMap<ModelSystem.PredictedSeries> -> float
<summary> Residual sum of squares. Provides a simple metric of distance between observed data and model predictions. </summary>
val compile: (ModelBuilder.ModelBuilder -> ModelSystem.ModelSystem)
val engine: EstimationEngine.EstimationEngine<float,float>
val mkContinuous: EstimationEngine.EstimationEngine<float,float>
<summary> A standard `EstimationEngine` for ordinary differential equation models. </summary>
val withCustomOptimisation: optim: EstimationEngine.Optimiser<'a> -> engine: EstimationEngine.EstimationEngine<'a,'b> -> EstimationEngine.EstimationEngine<'a,'b>
namespace Bristlecone.Optimisation
module Amoeba from Bristlecone.Optimisation
<summary> Nelder Mead implementation Adapted from original at: https://github.com/mathias-brandewinder/Amoeba </summary>
val swarm: levels: int -> amoebaAtLevel: int -> settings: Optimisation.Amoeba.Solver.Settings -> EstimationEngine.Optimiser<float>
<summary> Optimisation heuristic that creates a swarm of amoeba (Nelder-Mead) solvers. The swarm proceeds for `numberOfLevels` levels, constraining the starting bounds at each level to the 80th percentile of the current set of best likelihoods. </summary>
module Solver from Bristlecone.Optimisation.Amoeba
val Default: Optimisation.Amoeba.Solver.Settings
val testSettings: Test.TestSettings<float>
module Test from Bristlecone
type TestSettings<'a> = { TimeSeriesLength: int StartValues: CodedMap<'a> EndCondition: EndCondition<'a> GenerationRules: GenerationRule list NoiseGeneration: (Random -> Pool -> CodedMap<TimeSeries<'a>> -> Result<CodedMap<TimeSeries<'a>>,string>) EnvironmentalData: CodedMap<TimeSeries<'a>> Resolution: FixedTemporalResolution Random: Random StartDate: DateTime Attempts: int } static member Default: TestSettings<float>
Multiple items
val float: value: 'T -> float (requires member op_Explicit)

--------------------
type float = System.Double

--------------------
type float<'Measure> = float
val testResult: Result<Test.TestResult,string>
val testModel: engine: EstimationEngine.EstimationEngine<float,float> -> settings: Test.TestSettings<float> -> model: ModelSystem.ModelSystem -> Result<Test.TestResult,string>
<summary> **Description** Test that the specified estimation engine can correctly estimate known parameters. Random parameter sets are generated from the given model system. **Parameters** * `model` - a `ModelSystem` of equations and parameters * `testSettings` - settings * `engine` - an `EstimationEngine` </summary>

Type something to start searching.