cmdstan 0.1.8 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 30d42170e4611dc73b1c63623f02bed13c370ee3fa17545cc963714e76a81934
4
- data.tar.gz: 8a3de92029db9d781846d8c78d1fe6731d9a2834fdea266889338bff8e138824
3
+ metadata.gz: d2453efa50e8efc908919f7366531f5bde5d4c619c913360c2a13fe4b5cd131d
4
+ data.tar.gz: c0c185c461629fef5231c0378e655dc7f85dc89add5f20c990483a9951a1cb49
5
5
  SHA512:
6
- metadata.gz: bd7fa71f754207f5638977b63c66b19386c7b9fe60a708b3edb5da015c87af89abdd6f3a92e9b342a4dff3ec4cfa9a0754718260240140404adcb4905aa0b4c7
7
- data.tar.gz: 74b337113fcc1a34461b3086e62659b45719e8070b041bedc6f8ca442037be18a152bdedfaaaa747ca67ffca6e0ae2444a79d265e9a32807e0b6b5b8e5e41cd2
6
+ metadata.gz: d7741eeb4d5a61ba2f6bbd13039f2eac8ee44abe456d25b2785d02f6e974b98179d8e49f9e5ec255c86465b8a940121c6f7f152ea7278003f29542eb18847767
7
+ data.tar.gz: '052084d4bc7228885851cc2d8d9355272d97e98c40a8849938e3912411075c4410f16dcca20de3692460cdd5ae8d6d62ce96c1e18af13b358e96b175c0663f71'
data/CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
1
+ ## 0.2.1 (2022-07-06)
2
+
3
+ - Updated CmdStan to 2.30.0
4
+ - Fixed error when `chains` not specified
5
+
6
+ ## 0.2.0 (2022-04-23)
7
+
8
+ - CmdStan now installs when the first model is compiled rather than on gem installation
9
+ - Added `cmdstan_installed?` and `install_cmdstan` methods
10
+ - Updated CmdStan to 2.29.2
11
+ - Fixed issue with `summary` method
12
+ - Dropped support for Ruby < 2.7
13
+
14
+ ## 0.1.9 (2022-02-07)
15
+
16
+ - Added support for Linux ARM
17
+ - Updated CmdStan to 2.28.2
18
+
1
19
  ## 0.1.8 (2022-01-16)
2
20
 
3
21
  - Updated CmdStan to 2.28.1
data/README.md CHANGED
@@ -9,11 +9,9 @@ Bayesian inference for Ruby, powered by [CmdStan](https://github.com/stan-dev/cm
9
9
  Add this line to your application’s Gemfile:
10
10
 
11
11
  ```ruby
12
- gem 'cmdstan'
12
+ gem "cmdstan"
13
13
  ```
14
14
 
15
- Installation can take a few minutes as CmdStan downloads and builds.
16
-
17
15
  ## Getting Started
18
16
 
19
17
  Create a Stan file, like `bernoulli.stan`
@@ -32,7 +30,7 @@ model {
32
30
  }
33
31
  ```
34
32
 
35
- Compile the model
33
+ Compile the model (this can take a few minutes the first time as CmdStan downloads and builds)
36
34
 
37
35
  ```ruby
38
36
  model = CmdStan::Model.new(stan_file: "bernoulli.stan")
@@ -51,6 +49,14 @@ Summarize the results
51
49
  fit.summary
52
50
  ```
53
51
 
52
+ Load a compiled model
53
+
54
+ ```ruby
55
+ model = CmdStan::Model.new(exe_file: "bernoulli")
56
+ ```
57
+
58
+ Check out [Strata](https://github.com/ankane/strata) for shipping models
59
+
54
60
  ## Maximum Likelihood Estimation
55
61
 
56
62
  ```ruby
@@ -58,6 +64,20 @@ mle = model.optimize(data: data)
58
64
  mle.optimized_params
59
65
  ```
60
66
 
67
+ ## Reference
68
+
69
+ Check if CmdStan is installed
70
+
71
+ ```ruby
72
+ CmdStan.cmdstan_installed?
73
+ ```
74
+
75
+ Install CmdStan manually
76
+
77
+ ```ruby
78
+ CmdStan.install_cmdstan
79
+ ```
80
+
61
81
  ## Credits
62
82
 
63
83
  This library is modeled after the [CmdStanPy API](https://github.com/stan-dev/cmdstanpy).
@@ -81,6 +101,5 @@ To get started with development:
81
101
  git clone https://github.com/ankane/cmdstan-ruby.git
82
102
  cd cmdstan-ruby
83
103
  bundle install
84
- bundle exec ruby ext/cmdstan/extconf.rb
85
104
  bundle exec rake test
86
105
  ```
@@ -0,0 +1,100 @@
1
+ module CmdStan
2
+ module Install
3
+ def cmdstan_version
4
+ "2.30.0"
5
+ end
6
+
7
+ def cmdstan_installed?
8
+ Dir.exist?(CmdStan.path)
9
+ end
10
+
11
+ def install_cmdstan
12
+ version = cmdstan_version
13
+ dir = CmdStan.path
14
+
15
+ # no stanc3 binary for Mac ARM
16
+ if RbConfig::CONFIG["host_os"] !~ /darwin/i && RbConfig::CONFIG["host_cpu"] =~ /arm|aarch64/i
17
+ checksum = "8ab1eaa83af100336e31fed1bcb854f30e7f775feb1274552fc706ed177969ef"
18
+ url = "https://github.com/stan-dev/cmdstan/releases/download/v#{version}/cmdstan-#{version}-linux-arm64.tar.gz"
19
+ else
20
+ checksum = "009c2ea0043aa4a91c03ac78932e64f3cff4faa3e73413a2e0269d5be2d8de6c"
21
+ url = "https://github.com/stan-dev/cmdstan/releases/download/v#{version}/cmdstan-#{version}.tar.gz"
22
+ end
23
+
24
+ puts "Installing CmdStan version: #{version}"
25
+ puts "Install directory: #{dir}"
26
+
27
+ # only needed if default path
28
+ FileUtils.mkdir_p(File.expand_path("../../tmp", __dir__)) unless ENV["CMDSTAN"]
29
+
30
+ if Dir.exist?(dir)
31
+ puts "Already installed"
32
+ return true
33
+ end
34
+
35
+ Dir.mktmpdir do |tmpdir|
36
+ puts "Downloading..."
37
+ download_path = File.join(tmpdir, "cmdstan-#{version}.tar.gz")
38
+ download_file(url, download_path, checksum)
39
+
40
+ puts "Unpacking..."
41
+ path = File.join(tmpdir, "cmdstan-#{version}")
42
+ FileUtils.mkdir_p(path)
43
+ tar_args = Gem.win_platform? ? ["--force-local"] : []
44
+ system "tar", "xzf", download_path, "-C", path, "--strip-components=1", *tar_args
45
+
46
+ puts "Building..."
47
+ make_command = Gem.win_platform? ? "mingw32-make" : "make"
48
+ Dir.chdir(path) do
49
+ # disable precompiled header to save space
50
+ output, status = Open3.capture2e(make_command, "build", "PRECOMPILED_HEADERS=false")
51
+ if status.exitstatus != 0
52
+ puts output
53
+ raise Error, "Build failed"
54
+ end
55
+ end
56
+
57
+ FileUtils.mv(path, dir)
58
+ end
59
+
60
+ puts "Installed"
61
+
62
+ true
63
+ end
64
+
65
+ private
66
+
67
+ def download_file(url, download_path, checksum, redirects = 0)
68
+ raise Error, "Too many redirects" if redirects > 10
69
+
70
+ uri = URI(url)
71
+ location = nil
72
+
73
+ Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
74
+ request = Net::HTTP::Get.new(uri)
75
+ http.request(request) do |response|
76
+ case response
77
+ when Net::HTTPRedirection
78
+ location = response["location"]
79
+ when Net::HTTPSuccess
80
+ digest = Digest::SHA2.new
81
+
82
+ File.open(download_path, "wb") do |f|
83
+ response.read_body do |chunk|
84
+ f.write(chunk)
85
+ digest.update(chunk)
86
+ end
87
+ end
88
+
89
+ raise Error, "Bad checksum: #{digest.hexdigest}" if digest.hexdigest != checksum
90
+ else
91
+ raise Error, "Bad response"
92
+ end
93
+ end
94
+ end
95
+
96
+ # outside of Net::HTTP block to close previous connection
97
+ download_file(location, download_path, checksum, redirects + 1) if location
98
+ end
99
+ end
100
+ end
data/lib/cmdstan/mcmc.rb CHANGED
@@ -30,7 +30,7 @@ module CmdStan
30
30
  run_command "#{CmdStan.path}/bin/stansummary#{extension}", "--csv_filename=#{path}", *@output_files.map(&:path)
31
31
 
32
32
  result = {}
33
- CSV.foreach(path, headers: true, converters: :numeric) do |row|
33
+ CSV.foreach(path, skip_lines: /^#/, headers: true, converters: :numeric) do |row|
34
34
  value = row.to_h
35
35
  name = value.delete("name")
36
36
  result[name] = value if name == "lp__" || !name.end_with?("__")
data/lib/cmdstan/model.rb CHANGED
@@ -18,8 +18,12 @@ module CmdStan
18
18
  end
19
19
 
20
20
  def compile
21
+ unless ENV["CMDSTAN"] || CmdStan.cmdstan_installed?
22
+ CmdStan.install_cmdstan
23
+ end
24
+
21
25
  Dir.chdir(CmdStan.path) do
22
- run_command make_command, @exe_file
26
+ run_command make_command, @exe_file, "PRECOMPILED_HEADERS=false"
23
27
  end
24
28
  end
25
29
 
@@ -32,7 +36,7 @@ module CmdStan
32
36
  data_file.write(data.to_json)
33
37
  data_file.close
34
38
 
35
- chain ||= 4
39
+ chains ||= 4
36
40
 
37
41
  output_files = []
38
42
  chains.times do |chain|
@@ -1,3 +1,3 @@
1
1
  module CmdStan
2
- VERSION = "0.1.8"
2
+ VERSION = "0.2.1"
3
3
  end
data/lib/cmdstan.rb CHANGED
@@ -1,10 +1,14 @@
1
1
  # stdlib
2
+ require "digest"
2
3
  require "csv"
4
+ require "fileutils"
3
5
  require "json"
6
+ require "net/http"
4
7
  require "open3"
5
8
  require "tempfile"
6
9
 
7
10
  # modules
11
+ require "cmdstan/install"
8
12
  require "cmdstan/utils"
9
13
  require "cmdstan/mcmc"
10
14
  require "cmdstan/mle"
@@ -14,6 +18,8 @@ require "cmdstan/version"
14
18
  module CmdStan
15
19
  class Error < StandardError; end
16
20
 
21
+ extend Install
22
+
17
23
  class << self
18
24
  attr_accessor :path
19
25
  end
metadata CHANGED
@@ -1,28 +1,26 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cmdstan
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-17 00:00:00.000000000 Z
11
+ date: 2022-07-06 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email: andrew@ankane.org
15
15
  executables: []
16
- extensions:
17
- - ext/cmdstan/extconf.rb
16
+ extensions: []
18
17
  extra_rdoc_files: []
19
18
  files:
20
19
  - CHANGELOG.md
21
20
  - LICENSE.txt
22
21
  - README.md
23
- - ext/cmdstan/Makefile
24
- - ext/cmdstan/extconf.rb
25
22
  - lib/cmdstan.rb
23
+ - lib/cmdstan/install.rb
26
24
  - lib/cmdstan/mcmc.rb
27
25
  - lib/cmdstan/mle.rb
28
26
  - lib/cmdstan/model.rb
@@ -40,14 +38,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
40
38
  requirements:
41
39
  - - ">="
42
40
  - !ruby/object:Gem::Version
43
- version: '2.4'
41
+ version: '2.7'
44
42
  required_rubygems_version: !ruby/object:Gem::Requirement
45
43
  requirements:
46
44
  - - ">="
47
45
  - !ruby/object:Gem::Version
48
46
  version: '0'
49
47
  requirements: []
50
- rubygems_version: 3.3.3
48
+ rubygems_version: 3.3.7
51
49
  signing_key:
52
50
  specification_version: 4
53
51
  summary: Bayesian inference for Ruby, powered by CmdStan
data/ext/cmdstan/Makefile DELETED
@@ -1,5 +0,0 @@
1
- install:
2
- @echo "Nothing to do"
3
-
4
- clean:
5
- @echo "Nothing to do"
@@ -1,68 +0,0 @@
1
- require "digest"
2
- require "fileutils"
3
- require "net/http"
4
- require "tmpdir"
5
-
6
- version = "2.28.1"
7
- checksum = "eacadb4a1ca6997c9858e301780e729e53a9b5207b19ae2616abc882677e7637"
8
- url = "https://github.com/stan-dev/cmdstan/releases/download/v#{version}/cmdstan-#{version}.tar.gz"
9
-
10
- path = ENV["CMDSTAN"] || File.expand_path("../../tmp/cmdstan", __dir__)
11
- FileUtils.mkdir_p(path)
12
- raise "Directory not empty. Run: rake clean" unless Dir.empty?(path)
13
-
14
- $stdout.sync = true
15
-
16
- def download_file(url, download_path, checksum, redirects = 0)
17
- raise "Too many redirects" if redirects > 10
18
-
19
- uri = URI(url)
20
- location = nil
21
-
22
- Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
23
- request = Net::HTTP::Get.new(uri)
24
- http.request(request) do |response|
25
- case response
26
- when Net::HTTPRedirection
27
- location = response["location"]
28
- when Net::HTTPSuccess
29
- digest = Digest::SHA2.new
30
-
31
- i = 0
32
- File.open(download_path, "wb") do |f|
33
- response.read_body do |chunk|
34
- f.write(chunk)
35
- digest.update(chunk)
36
-
37
- # print progress
38
- putc "." if i % 50 == 0
39
- i += 1
40
- end
41
- end
42
- puts # newline
43
-
44
- abort "Bad checksum: #{digest.hexdigest}" if digest.hexdigest != checksum
45
- else
46
- abort "Bad response"
47
- end
48
- end
49
- end
50
-
51
- # outside of Net::HTTP block to close previous connection
52
- download_file(location, download_path, checksum, redirects + 1) if location
53
- end
54
-
55
- # download
56
- puts "Downloading #{url}..."
57
- download_path = "#{Dir.tmpdir}/cmdstan-#{version}.tar.gz"
58
- download_file(url, download_path, checksum)
59
-
60
- # extract
61
- Dir.chdir(path)
62
- # TODO use Gem::Package::TarReader from Rubygems
63
- tar_args = Gem.win_platform? ? ["--force-local"] : []
64
- system "tar", "zxf", download_path, "-C", path, "--strip-components=1", *tar_args
65
-
66
- # build
67
- make_command = Gem.win_platform? ? "mingw32-make" : "make"
68
- system make_command, "build"