cmdstan 0.1.8 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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"