[DRE-commits] [ruby-integration] 01/08: New upstream version 0.1.4
Lucas Moura
lucasmoura-guest at moszumanska.debian.org
Wed Feb 8 17:47:02 UTC 2017
This is an automated email from the git hooks/post-receive script.
lucasmoura-guest pushed a commit to branch master
in repository ruby-integration.
commit 230f21db5e950f0de8643b87c8218333b01bbc44
Author: Lucas Albuquerque Medeiros de Moura <lucas.moura128 at gmail.com>
Date: Wed Feb 8 15:22:41 2017 -0200
New upstream version 0.1.4
---
.autotest | 23 --
.gemtest | 0
.gitignore | 8 +
.travis.yml | 16 ++
.yardopts | 4 +
CONTRIBUTING.md | 61 ++++++
Gemfile | 5 +
History.txt | 20 +-
Manifest.txt | 9 -
README.md | 74 +++++++
README.txt | 60 -----
Rakefile | 40 ++--
benchmark/accuracy.rb | 24 ++
benchmark/speed.rb | 20 ++
data.tar.gz.sig | Bin 256 -> 0 bytes
integration.gemspec | 29 +++
lib/integration.rb | 426 ++++++++++++------------------------
lib/integration/methods.rb | 394 +++++++++++++++++++++++++++++++++
lib/integration/version.rb | 3 +
lib/opencl/Makefile | 29 +++
lib/opencl/integration_host.c | 151 +++++++++++++
lib/opencl/opencl_minimization.rb | 251 +++++++++++++++++++++
lib/opencl/unidimensional_kernel.cl | 47 ++++
metadata.gz.sig | 1 -
metadata.yml | 203 ++++++++---------
spec/integration_spec.rb | 94 ++++----
spec/spec.opts | 3 -
spec/spec_helper.rb | 27 ++-
28 files changed, 1475 insertions(+), 547 deletions(-)
diff --git a/.autotest b/.autotest
deleted file mode 100644
index ef753ad..0000000
--- a/.autotest
+++ /dev/null
@@ -1,23 +0,0 @@
-# -*- ruby -*-
-
-require 'autotest/restart'
-
-# Autotest.add_hook :initialize do |at|
-# at.extra_files << "../some/external/dependency.rb"
-#
-# at.libs << ":../some/external"
-#
-# at.add_exception 'vendor'
-#
-# at.add_mapping(/dependency.rb/) do |f, _|
-# at.files_matching(/test_.*rb$/)
-# end
-#
-# %w(TestA TestB).each do |klass|
-# at.extra_class_map[klass] = "test/test_misc.rb"
-# end
-# end
-
-# Autotest.add_hook :run_command do |at|
-# system "rake build"
-# end
diff --git a/.gemtest b/.gemtest
deleted file mode 100644
index e69de29..0000000
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..05f1367
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+*~
+Gemfile.lock
+coverage/*
+pkg/*
+
+doc/
+.yardoc/
+
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..bfab0cd
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,16 @@
+language: ruby
+rvm:
+ - 1.9.3
+ - 2.0
+ - 2.1
+ - 2.2
+# - jruby-19mode # JRuby in 1.9 mode -> Problems with bigint
+# - rbx-19mode
+# script: bundle exec rspec spec
+
+script:
+ bundle exec rake spec
+
+before_install:
+ - sudo apt-get update -qq
+ - sudo apt-get install -y libgsl0-dev
diff --git a/.yardopts b/.yardopts
new file mode 100644
index 0000000..c2be80d
--- /dev/null
+++ b/.yardopts
@@ -0,0 +1,4 @@
+--title "Integration"
+--markup markdown
+lib/**/*.rb
+README.md History.txt
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..8c74ea0
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,61 @@
+Integration is part of SciRuby, a collaborative effort to bring scientific computation to Ruby. If you want to help, please
+do so!
+
+This guide covers ways in which you can contribute to the development of SciRuby and, more specifically, Integration.
+
+## How to help
+
+There are various ways to help Integration: bug reports, coding and documentation. All of them are important.
+
+First, you can help implement new features or bug fixes. To do that, visit our [issue tracker][2]. If you find something that you want to work on, post it in the issue or on our [mailing list][1].
+
+You need to send tests together with your code. No exceptions. You can ask for our opinion, but we won't accept patches without good spec coverage.
+
+We use RSpec for testing. If you aren't familiar with it, there's a good [guide to better specs with RSpec](http://betterspecs.org/) that shows a bit of the syntax and how to use it properly.
+However, the best resource is probably the specs that already exist -- so just read them.
+
+And don't forget to write documentation (we use YARD). It's necessary to allow others to know what's available in the library. There's a section on it later in this guide.
+
+We only accept bug reports and pull requests in GitHub. You'll need to create a new (free) account if you don't have one already. To learn how to create a pull request, please see [this guide on collaborating](https://help.github.com/categories/63/articles).
+
+If you have a question about how to use Integration or SciRuby in general or a feature/change in mind, please ask the [sciruby-dev mailing list][1].
+
+Thanks!
+
+## Coding
+
+To start working on Integration, clone the repository and use bundler to install the dependencies:
+
+```bash
+$ git clone git://github.com/SciRuby/integration.git
+$ cd integration
+$ bundle install
+```
+
+If everything's fine until now, you can create a new branch to work on your feature:
+
+```bash
+$ git branch new-feature
+$ git checkout new-feature
+```
+
+Before commiting any code, please read our
+[Contributor Agreement](http://github.com/SciRuby/sciruby/wiki/Contributor-Agreement).
+
+## Style guide
+
+Follow the [GitHub styleguide](https://github.com/styleguide/ruby). If you have any doubt, contact us.
+
+## Documentation
+
+We are using [YARD](http://yardoc.org/) for documenting the source. There is still a lot to do: more references, more examples, better names for parameters, etc. We accept patches for each and every one of these problems -- if you want to send a patch improving documentation, we will be pleased to review it!
+
+See the [YARD guides](http://www.yardoc.org/guides/index.html) for more information.
+
+## Conclusion
+
+This guide was heavily based on the
+[Contributing to Ruby on Rails guide](http://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html).
+
+[1]: https://groups.google.com/forum/?fromgroups#!forum/sciruby-dev
+[2]: https://github.com/sciruby/integration/issues
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..f37c869
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,5 @@
+source "https://www.rubygems.org"
+
+gem 'rb-gsl', '~> 1.16'
+
+gemspec
diff --git a/History.txt b/History.txt
index 51ddfc2..aa13a4f 100644
--- a/History.txt
+++ b/History.txt
@@ -1,3 +1,19 @@
-=== 0.1.0 / 2011-08-23
+=== 0.1.4 / 2015-05-23
+ * GSL will be used if available. The tests will only pass if rb-gsl is installed.
+ * Specs depending on GSL will fail without `rb-gsl` installed.
+ * Added CONTRIBUTING.md file.
+
+=== 0.1.3 / 2015-05-22
+ * Remove rb-gsl dependency.
+
+=== 0.1.2 / 2015-03-29
+ * Minor upgrade.
+ * Removed old files from the repository.
-* Get code from http://rubyforge.org/projects/integral/ and converted to a gem.
+=== 0.1.1 / 2014-08-09
+ * New version, with methods ruby methods: rectangle, :trapezoid, :simpson,
+ :adaptive_quadrature , :gauss, :romberg, :monte_carlo, :gauss_kronrod,
+ :simpson3by8, :boole, :open_trapezoid, :milne.
+
+=== 0.1.0 / 2011-08-23
+ * Get code from http://rubyforge.org/projects/integral/ and converted to a gem.
diff --git a/Manifest.txt b/Manifest.txt
deleted file mode 100644
index b23b9ea..0000000
--- a/Manifest.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-.autotest
-History.txt
-Manifest.txt
-README.txt
-Rakefile
-lib/integration.rb
-spec/integration_spec.rb
-spec/spec.opts
-spec/spec_helper.rb
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..a6d9121
--- /dev/null
+++ b/README.md
@@ -0,0 +1,74 @@
+# Integration
+
+[](https://travis-ci.org/SciRuby/integration)
+[](https://codeclimate.com/github/SciRuby/integration)
+
+Numerical integration for Ruby, with a simple interface. Several different integration methods are implemented.
+
+## Installation
+
+```bash
+$ gem install integration
+```
+
+You can install GSL (please use your package manager) for better performance and support for infinite bounds. After successfully installing the library:
+
+```bash
+$ gem install rb-gsl
+```
+
+## Documentation
+
+You can see the latest documentation for Integration at Rubydoc: [rubydoc.info/github/sciruby/integration](http://www.rubydoc.info/github/sciruby/integration).
+
+## Features
+
+* Use only one method: Integration.integrate
+* Rectangular, Trapezoidal, Simpson, Adaptive quadrature, Monte Carlo and Romberg integration methods available on pure Ruby.
+* If available, uses Ruby/GSL QNG non-adaptive Gauss-Kronrod integration and QAG adaptive integration, with support for Infinity+ and Infinity-
+
+## Examples
+
+```ruby
+# Integrate x^2 in [1, 2] using Simpson's rule.
+Integration.integrate(1, 2, tolerance: 1e-10, method: :simpson) do |x|
+ x**2
+end
+# => 2.333333
+
+# Support for infinity bounds with GSL QAG adaptative integration.
+
+normal_pdf = lambda do |x|
+ (1 / Math.sqrt(2 * Math::PI)) * Math.exp(-0.5 * (x**2))
+end
+
+Integration.integrate(Integration::MInfinity, 0, tolerance: 1e-10, &normal_pdf) # => 0.5
+Integration.integrate(0, Integration::Infinity , tolerance: 1e-10, &normal_pdf) # => 0.5
+```
+
+## License
+
+Copyright (c) 2005 Beng
+ 2011-2015 clbustos
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE DEVELOPERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+Except as contained in this notice, the name of the Beng shall not
+be used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from Beng.
diff --git a/README.txt b/README.txt
deleted file mode 100644
index 884c4a1..0000000
--- a/README.txt
+++ /dev/null
@@ -1,60 +0,0 @@
-= integration
-
-* http://github.com/clbustos/integration
-
-== DESCRIPTION:
-
-Numerical integration for Ruby, with a simple interface
-
-== FEATURES/PROBLEMS:
-
-* Use only one method: Integration.integrate
-* Rectangular, Trapezoidal, Simpson, Adaptive quadrature, Monte Carlo and Romberg integration methods available on pure Ruby.
-* If available, uses Ruby/GSL QNG non-adaptive Gauss-Kronrod integration and QAG adaptive integration, with support for Infinity+ and Infinity-
-
-
-== SYNOPSIS:
-
- Integration.integrate(1,2,{:tolerance=>1e-10,:method=>:simpson}) {|x| x**2} => 2.333333
-
- # Support for infinity bounds with GSL QAG adaptative integration
-
- normal_pdf=lambda {|x| (1/Math.sqrt(2*Math::PI))*Math.exp(-(x**2/2))}
- Integration.integrate(Integration::MInfinity, 0 , {:tolerance=>1e-10}, &normal_pdf) => 0.5
- Integration.integrate(0, Integration::Infinity , {:tolerance=>1e-10}, &normal_pdf) => 0.5
-
-== REQUIREMENTS:
-
-* Ruby/GSL, for better performance and support for infinite bounds
-
-== INSTALL:
-
- gem install integration
-
-== LICENSE:
-
- Copyright (c) 2005 Beng
- 2011 clbustos
-
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the "Software"),
- to deal in the Software without restriction, including without limitation
- the rights to use, copy, modify, merge, publish, distribute, sublicense,
- and/or sell copies of the Software, and to permit persons to whom the
- Software is furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- THE DEVELOPERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
- OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-
- Except as contained in this notice, the name of the Beng shall not
- be used in advertising or otherwise to promote the sale, use or other dealings
- in this Software without prior written authorization from Beng.
-
diff --git a/Rakefile b/Rakefile
index fb92fb7..16add4c 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,23 +1,25 @@
-# -*- ruby -*-
-$:.unshift(File.expand_path(File.dirname(__FILE__)+"/lib/"))
-require 'rubygems'
-require 'hoe'
-require 'integration'
-require 'rubyforge'
-# Hoe.plugin :compiler
-# Hoe.plugin :gem_prelude_sucks
- Hoe.plugin :git
-# Hoe.plugin :inline
-# Hoe.plugin :racc
-# Hoe.plugin :rubyforge
+$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
-Hoe.spec 'integration' do
- self.developer('Ben Gimpert', 'NO_EMAIL')
- self.developer('Claudio Bustos', 'clbustos_at_gmail.com')
- self.version=Integration::VERSION
- self.extra_dev_deps << ["rspec",">=2.0"] << ["rubyforge",">=0"]
+require 'integration/version'
+require 'bundler'
+require 'bundler/gem_tasks'
+require 'rspec/core/rake_task'
+begin
+ Bundler.setup(:default, :development)
+rescue Bundler::BundlerError => e
+ $stderr.puts e.message
+ $stderr.puts "Run `bundle install` to install missing gems"
+ exit e.status_code
end
-# git log --pretty=format:"*%s[%cn]" v0.5.0..HEAD >> History.txt
-# vim: syntax=ruby
+RSpec::Core::RakeTask.new(:spec) do |spec|
+ spec.pattern = FileList['spec/**/*_spec.rb']
+end
+
+desc "Open an irb session preloaded with integration"
+task :console do
+ sh "irb -rubygems -I lib -r integration.rb"
+end
+
+task :default => :spec
diff --git a/benchmark/accuracy.rb b/benchmark/accuracy.rb
new file mode 100644
index 0000000..6888b7e
--- /dev/null
+++ b/benchmark/accuracy.rb
@@ -0,0 +1,24 @@
+# Comparing the accuracy of different integraiton methods
+# text table is required to display the results in a nice table
+require 'integration'
+require 'text-table'
+
+# put the funtion you want to benchmark here
+func = lambda{|x| x}
+#put the actual result of the integration here
+actual_result = 5/2.0 + 2* Math::sin(1)
+
+table = Text::Table.new
+table.head = ['Method','Result','Actual Result','Error','Accuracy']
+
+for method in [:rectangle,:trapezoid,:simpson,:romberg,:adaptive_quadrature, :gauss, :gauss_kronrod, :simpson3by8, :boole, :open_trapezoid, :milne,:qng, :qag]
+ result = Integration.integrate(0,1,{:method=>method},&func)
+ if result == nil
+ puts method
+ else
+ error = (actual_result-result).abs
+ table.rows << [method,result,actual_result,error,100*(1-error/actual_result.to_f)]
+ end
+end
+puts table.to_s
+
diff --git a/benchmark/speed.rb b/benchmark/speed.rb
new file mode 100644
index 0000000..7afd1d3
--- /dev/null
+++ b/benchmark/speed.rb
@@ -0,0 +1,20 @@
+# Checking the speed of different integraiton methods
+
+require 'benchmark'
+require 'integration'
+
+# set the number of iterations
+iterations = 100
+puts "Benchmarking with #{iterations} iterations"
+
+# put the function to be benchmarked here
+func = lambda{|x| x}
+for method in [:rectangle,:trapezoid,:simpson,:romberg, :adaptive_quadrature, :gauss, :gauss_kronrod, :simpson3by8, :boole, :open_trapezoid, :milne, :qng, :qag]
+ Benchmark.bm(25) do |bm|
+ bm.report(method.to_s) do
+ iterations.times do
+ Integration.integrate(0,1,{:method=>method},&func)
+ end
+ end
+ end
+end
diff --git a/data.tar.gz.sig b/data.tar.gz.sig
deleted file mode 100644
index 60afcea..0000000
Binary files a/data.tar.gz.sig and /dev/null differ
diff --git a/integration.gemspec b/integration.gemspec
new file mode 100644
index 0000000..c3bcab6
--- /dev/null
+++ b/integration.gemspec
@@ -0,0 +1,29 @@
+$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
+
+require 'integration/version'
+
+Gem::Specification.new do |s|
+ s.name = 'integration'
+ s.version = Integration::VERSION
+
+ s.authors = ['Claudio Bustos', 'Ben Gimpert']
+ s.email = ['clbustos at gmail.com']
+ s.homepage = 'http://sciruby.com'
+
+ s.summary = 'Numerical integration for Ruby with a simple interface.'
+ s.description = 'Numerical integration for Ruby with a simple interface.'
+ s.license = 'See README.md.'
+
+ s.files = `git ls-files`.split("\n")
+ s.test_files = `git ls-files -- {test,spec,features,benchmark}/*`.split("\n")
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
+ s.require_paths = ['lib']
+
+ s.required_ruby_version = '>= 1.9.3'
+
+ s.add_runtime_dependency 'text-table', '~> 1.2'
+
+ s.add_development_dependency 'bundler', '>= 1.3.0', '< 2.0'
+ s.add_development_dependency 'rake', '~> 10.4'
+ s.add_development_dependency 'rspec', '~> 3.2'
+end
diff --git a/lib/integration.rb b/lib/integration.rb
index ecddacb..d05d507 100644
--- a/lib/integration.rb
+++ b/lib/integration.rb
@@ -1,16 +1,16 @@
# Copyright (c) 2005 Beng (original code)
-# 2011 clbustos
-#
+# 2011 Claudio Bustos
+# XXXX -> Add new developers
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
-#
+#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
-#
+#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
@@ -18,323 +18,183 @@
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
-#
+#
# Except as contained in this notice, the name of the Beng shall not
# be used in advertising or otherwise to promote the sale, use or other dealings
# in this Software without prior written authorization from Beng.
+require 'integration/methods'
+
# Diverse integration methods
# Use Integration.integrate as wrapper to direct access to methods
-#
-# Method API
#
-
class Integration
- VERSION = '0.1.0'
+
# Minus Infinity
- MInfinity=:minfinity
+ MInfinity = :minfinity
+
# Infinity
- Infinity=:infinity
+ Infinity = :infinity
+
+ # Pure Ruby methods available.
+ RUBY_METHODS = [:rectangle, :trapezoid, :simpson, :adaptive_quadrature,
+ :gauss, :romberg, :monte_carlo, :gauss_kronrod,
+ :simpson3by8, :boole, :open_trapezoid, :milne]
+
+ # Methods available when using the `rb-gsl` gem.
+ GSL_METHODS = [:qng, :qag]
+
class << self
-
- # Create a method 'has_<library>' on Module
- # which require a library and return true or false
- # according to success of failure
- def create_has_library(library) #:nodoc:
- define_singleton_method("has_#{library}?") do
- cv="@@#{library}"
- if !class_variable_defined? cv
- begin
- require library.to_s
- class_variable_set(cv, true)
- rescue LoadError
- class_variable_set(cv, false)
- end
- end
- class_variable_get(cv)
- end
- end
-
- # Rectangle method
- # +n+ implies number of subdivisions
- def rectangle(t1, t2, n)
- total_area = 0
- t = t1
- dt = (t2 - t1) / n.to_f
- dt_half = dt / 2
-
- while (t + dt_half) <= t2
- height = yield(t + dt_half)
- area = dt * height
- total_area += area
- t += dt
- end
- return total_area
+ # Check if `value` is plus or minus infinity.
+ #
+ # @param value Value to be tested.
+ def infinite?(value)
+ value == Integration::Infinity || value == Integration::MInfinity
end
- alias_method :midpoint, :rectangle
-
- def trapezoid(t1, t2, n)
- total_area = 0
- t = t1
- dt = (t2 - t1) / n.to_f
- prev_height = nil
- while (t + dt) <= t2
- if prev_height.nil?
- height1 = yield(t)
- else
- height1 = prev_height
- end
- height2 = yield(t + dt)
- area = dt * ((height1 + height2) / 2)
- total_area += area
- t += dt
- prev_height = height2
- end
- return total_area
- end
-
- def simpson(t1, t2, n)
- n += 1 unless n % 2 == 0
- dt = (t2.to_f - t1) / n
- total_area = 0
- (0..n).each do |i|
- t = t1 + (dt * i)
- if i.zero? || (i == n)
- total_area += yield(t)
- elsif i % 2 == 0
- total_area += 2 * yield(t)
- else
- total_area += 4 * yield(t)
- end
- end
- total_area *= dt / 3
- return total_area
- end
-
- def adaptive_quadrature(a, b, tolerance)
- h = (b.to_f - a) / 2
- fa = yield(a)
- fc = yield(a + h)
- fb = yield(b)
- s = h * (fa + (4 * fc) + fb) / 3
- helper = Proc.new { |a, b, fa, fb, fc, h, s, level|
- if level < 1/tolerance.to_f
- fd = yield(a + (h / 2))
- fe = yield(a + (3 * (h / 2)))
- s1 = h * (fa + (4.0 * fd) + fc) / 6
- s2 = h * (fc + (4.0 * fe) + fb) / 6
- if ((s1 + s2) - s).abs <= tolerance
- s1 + s2
- else
- helper.call(a, a + h, fa, fc, fd, h / 2, s1, level + 1) +
- helper.call(a + h, b, fc, fb, fe, h / 2, s2, level + 1)
- end
- else
- raise "Integral did not converge"
- end
- }
- return helper.call(a, b, fa, fb, fc, h, s, 1)
- end
-
- def gauss(t1, t2, n)
- case n
- when 1
- z = [0.0]
- w = [2.0]
- when 2
- z = [-0.57735026919, 0.57735026919]
- w = [1.0, 1.0]
- when 3
- z = [-0.774596669241, 0.0, 0.774596669241]
- w = [0.555555555556, 0.888888888889, 0.555555555556]
- when 4
- z = [-0.861136311594, -0.339981043585, 0.339981043585, 0.861136311594]
- w = [0.347854845137, 0.652145154863, 0.652145154863, 0.347854845137]
- when 5
- z = [-0.906179845939, -0.538469310106, 0.0, 0.538469310106, 0.906179845939]
- w = [0.236926885056, 0.478628670499, 0.568888888889, 0.478628670499, 0.236926885056]
- when 6
- z = [-0.932469514203, -0.661209386466, -0.238619186083, 0.238619186083, 0.661209386466, 0.932469514203]
- w = [0.171324492379, 0.360761573048, 0.467913934573, 0.467913934573, 0.360761573048, 0.171324492379]
- when 7
- z = [-0.949107912343, -0.741531185599, -0.405845151377, 0.0, 0.405845151377, 0.741531185599, 0.949107912343]
- w = [0.129484966169, 0.279705391489, 0.381830050505, 0.417959183673, 0.381830050505, 0.279705391489, 0.129484966169]
- when 8
- z = [-0.960289856498, -0.796666477414, -0.525532409916, -0.183434642496, 0.183434642496, 0.525532409916, 0.796666477414, 0.960289856498]
- w = [0.10122853629, 0.222381034453, 0.313706645878, 0.362683783378, 0.362683783378, 0.313706645878, 0.222381034453, 0.10122853629]
- when 9
- z = [-0.968160239508, -0.836031107327, -0.613371432701, -0.324253423404, 0.0, 0.324253423404, 0.613371432701, 0.836031107327, 0.968160239508]
- w = [0.0812743883616, 0.180648160695, 0.260610696403, 0.31234707704, 0.330239355001, 0.31234707704, 0.260610696403, 0.180648160695, 0.0812743883616]
- when 10
- z = [-0.973906528517, -0.865063366689, -0.679409568299, -0.433395394129, -0.148874338982, 0.148874338982, 0.433395394129, 0.679409568299, 0.865063366689, 0.973906528517]
- w = [0.0666713443087, 0.149451349151, 0.219086362516, 0.26926671931, 0.295524224715, 0.295524224715, 0.26926671931, 0.219086362516, 0.149451349151, 0.0666713443087]
- else
- raise "Invalid number of spaced abscissas #{n}, should be 1-10"
- end
- sum = 0
- (0...n).each do |i|
- t = ((t1.to_f + t2) / 2) + (((t2 - t1) / 2) * z[i])
- sum += w[i] * yield(t)
- end
- return ((t2 - t1) / 2.0) * sum
- end
-
- def romberg(a, b, tolerance)
- # NOTE one-based arrays are used for convenience
-
- h = b.to_f - a
- m = 1
- close = 1
- r = [[], [], [], [], [], [], [], [], [], [], [], [], []];
- r[1][1] = (h / 2) * (yield(a) + yield(b))
- j = 1
- while j <= 11 && tolerance < close
- j += 1
- r[j][0] = 0
- h /= 2
- sum = 0
- (1..m).each do |k|
- sum += yield(a + (h * ((2 * k) - 1)))
- end
- m *= 2
- r[j][1] = r[j-1][1] / 2 + (h * sum)
- (1..j-1).each do |k|
- r[j][k+1] = r[j][k] + ((r[j][k] - r[j-1][k]) / ((4 ** k) - 1))
- end
- close = (r[j][j] - r[j-1][j-1])
- end
- return r[j][j]
- end
-
- def monte_carlo(t1, t2, n)
- width = (t2 - t1).to_f
- height = nil
- vals = []
- n.times do
- t = t1 + (rand() * width)
- ft = yield(t)
- height = ft if height.nil? || ft > height
- vals << ft
- end
- area_ratio = 0
- vals.each do |ft|
- area_ratio += (ft / height.to_f) / n.to_f
- end
- return (width * height) * area_ratio
- end
- def is_infinite?(v)
- v==Infinity or v==MInfinity
- end
- # Methods available on pure ruby
- RUBY_METHOD=[:rectangle,:trapezoid,:simpson, :adaptive_quadrature , :gauss, :romberg, :monte_carlo]
- # Methods available with Ruby/GSL library
- GSL_METHOD=[:qng, :qag]
- # Get the integral for a function +f+, with bounds +t1+ and
- # +t2+ given a hash of +options+.
- # If Ruby/GSL is available, you could use +Integration::Minfinity+
- # and +Integration::Infinity+ as bounds. Method
- # Options are
+
+ # Get the integral for a function +f+, with bounds +t1+ and +t2+ given a
+ # hash of +options+. If Ruby/GSL is available, you can use
+ # +Integration::Minfinity+ and +Integration::Infinity+ as bounds. Method
+ #
+ # Options are:
# [:tolerance] Maximum difference between real and calculated integral.
- # Default: 1e-10
- # [:initial_step] Initial number of subdivitions
- # [:step] Subdivitions increment on each iteration
- # [:method] Integration method.
- # Methods are
- # [:rectangle] for [:initial_step+:step*iteration] quadrilateral subdivisions
- # [:trapezoid] for [:initial_step+:step*iteration] trapezoid-al subdivisions
- # [:simpson] for [:initial_step+:step*iteration] parabolic subdivisions
- # [:adaptive_quadrature] for recursive appoximations until error [tolerance]
- # [:gauss] [:initial_step+:step*iteration] weighted subdivisons using translated -1 -> +1 endpoints
- # [:romberg] extrapolation of recursion approximation until error < [tolerance]
- # [:monte_carlo] make [:initial_step+:step*iteration] random samples, and check for above/below curve
- # [:qng] GSL QNG non-adaptive Gauss-Kronrod integration
- # [:qag] GSL QAG adaptive integration, with support for infinite bounds
- def integrate(t1,t2,options=Hash.new, &f)
- inf_bounds=(is_infinite?(t1) or is_infinite?(t2))
- raise "No function passed" unless block_given?
- raise "Non-numeric bounds" unless ((t1.is_a? Numeric) and (t2.is_a? Numeric)) or inf_bounds
- if(inf_bounds)
- lower_bound=t1
- upper_bound=t2
- options[:method]=:qag if options[:method].nil?
- else
+ # Default: 1e-10.
+ # [:initial_step] Initial number of subdivisions.
+ # [:step] Subdivition increment on each iteration.
+ # [:method] Integration method.
+ #
+ # Available methods are:
+ #
+ # [:rectangle] for [:initial_step+:step*iteration] quadrilateral subdivisions.
+ # [:trapezoid] for [:initial_step+:step*iteration] trapezoid-al subdivisions.
+ # [:simpson] for [:initial_step+:step*iteration] parabolic subdivisions.
+ # [:adaptive_quadrature] for recursive appoximations until error [tolerance].
+ # [:gauss] [:initial_step+:step*iteration] weighted subdivisons using
+ # translated -1 -> +1 endpoints.
+ # [:romberg] extrapolation of recursion approximation until error < [tolerance].
+ # [:monte_carlo] make [:initial_step+:step*iteration] random samples, and
+ # check for above/below curve.
+ # [:qng] GSL QNG non-adaptive Gauss-Kronrod integration.
+ # [:qag] GSL QAG adaptive integration, with support for infinite bounds.
+ def integrate(t1, t2, options = {}, &f)
+ inf_bounds = (infinite?(t1) || infinite?(t2))
+
+ fail 'No function passed' unless block_given?
+ fail 'Non-numeric bounds' unless ((t1.is_a? Numeric) && (t2.is_a? Numeric)) || inf_bounds
+
+ if inf_bounds
+ lower_bound = t1
+ upper_bound = t2
+ options[:method] = :qag if options[:method].nil?
+ else
lower_bound = [t1, t2].min
upper_bound = [t1, t2].max
end
- def_method=(has_gsl?) ? :qag : :simpson
- default_opts={:tolerance=>1e-10, :initial_step=>16,:step=>16, :method=>def_method}
- options=default_opts.merge(options)
- if RUBY_METHOD.include? options[:method]
- raise "Ruby methods doesn't support infinity bounds" if inf_bounds
- integrate_ruby(lower_bound,upper_bound,options,&f)
- elsif GSL_METHOD.include? options[:method]
- integrate_gsl(lower_bound,upper_bound,options,&f)
+
+ def_method = (Integration.has_gsl?) ? :qag : :simpson
+ default_opts = { tolerance: 1e-10, initial_step: 16, step: 16, method: def_method }
+ options = default_opts.merge(options)
+
+ if RUBY_METHODS.include? options[:method]
+ fail "Ruby methods doesn't support infinity bounds" if inf_bounds
+ integrate_ruby(lower_bound, upper_bound, options, &f)
+ elsif GSL_METHODS.include? options[:method]
+ integrate_gsl(lower_bound, upper_bound, options, &f)
else
- raise "Unknown integration method \"#{options[:method]}\""
+ fail "Unknown integration method \"#{options[:method]}\""
end
end
- def integrate_gsl(lower_bound,upper_bound,options,&f)
-
+
+ # Integrate using the GSL bindings.
+ def integrate_gsl(lower_bound, upper_bound, options, &f)
f = GSL::Function.alloc(&f)
- method=options[:method]
- tolerance=options[:tolerance]
-
- if(method==:qag)
- w = GSL::Integration::Workspace.alloc()
- if(is_infinite?(lower_bound) and is_infinite?(upper_bound))
- #puts "ambos"
- val=f.qagi([tolerance,0.0], 1000, w)
- elsif is_infinite?(lower_bound)
- #puts "inferior #{upper_bound}"
- val=f.qagil(upper_bound, [tolerance, 0], w)
- elsif is_infinite?(upper_bound)
- #puts "superior"
- val=f.qagiu(lower_bound, [tolerance, 0], w)
+ method = options[:method]
+ tolerance = options[:tolerance]
+
+ if (method == :qag)
+ w = GSL::Integration::Workspace.alloc
+
+ val = if infinite?(lower_bound) && infinite?(upper_bound)
+ f.qagi([tolerance, 0.0], 1000, w)
+ elsif infinite?(lower_bound)
+ f.qagil(upper_bound, [tolerance, 0], w)
+ elsif infinite?(upper_bound)
+ f.qagiu(lower_bound, [tolerance, 0], w)
else
-
- val=f.qag([lower_bound,upper_bound],[tolerance,0.0], GSL::Integration::GAUSS61, w)
+ f.qag([lower_bound, upper_bound], [tolerance, 0.0], GSL::Integration::GAUSS61, w)
end
- elsif(method==:qng)
- val=f.qng([lower_bound, upper_bound], [tolerance, 0.0])
+
+ elsif (method == :qng)
+ val = f.qng([lower_bound, upper_bound], [tolerance, 0.0])
+
else
- raise "Unknown integration method \"#{method}\""
+ fail "Unknown integration method \"#{method}\""
end
+
val[0]
end
- def integrate_ruby(lower_bound,upper_bound,options,&f)
- method=options[:method]
- tolerance=options[:tolerance]
- initial_step=options[:initial_step]
- step=options[:step]
-
+
+ def integrate_ruby(lower_bound, upper_bound, options, &f)
+ method = options[:method]
+ tolerance = options[:tolerance]
+ initial_step = options[:initial_step]
+ step = options[:step]
+ points = options[:points]
+
begin
method_obj = Integration.method(method.to_s.downcase)
rescue
raise "Unknown integration method \"#{method}\""
end
- current_step=initial_step
- if(method==:adaptive_quadrature or method==:romberg or method==:gauss)
- if(method==:gauss)
- initial_step=10 if initial_step>10
- tolerance=initial_step
+ current_step = initial_step
+
+ if [:adaptive_quadrature, :romberg, :gauss, :gauss_kronrod].include? method
+ if (method == :gauss)
+ initial_step = 10 if initial_step > 10
+ tolerance = initial_step
+ method_obj.call(lower_bound, upper_bound, tolerance, &f)
+ elsif (method == :gauss_kronrod)
+ initial_step = 10 if initial_step > 10
+ tolerance = initial_step
+ points = points unless points.nil?
+ method_obj.call(lower_bound, upper_bound, tolerance, points, &f)
+ else
+ method_obj.call(lower_bound, upper_bound, tolerance, &f)
end
- method_obj.call(lower_bound, upper_bound, tolerance, &f)
else
- #puts "iniciando"
- value=method_obj.call(lower_bound, upper_bound, current_step, &f)
- previous=value+(tolerance*2)
- while((previous-value).abs > tolerance) do
- #puts(value)
- #puts(current_step)
- current_step+=step
- previous=value
- value=method_obj.call(lower_bound, upper_bound, current_step, &f)
+ value = method_obj.call(lower_bound, upper_bound, current_step, &f)
+ previous = value + (tolerance * 2)
+ diffs = []
+
+ while (previous - value).abs > tolerance
+ diffs.push((previous - value).abs)
+ current_step += step
+ previous = value
+ value = method_obj.call(lower_bound, upper_bound, current_step, &f)
end
+
value
end
end
+
+ # Check if GSL is available. Require the library if it is present. Return a
+ # boolean indicating its availability.
+ #
+ # @return [Boolean] Whether GSL is available.
+ def has_gsl?
+ gsl_available = '@@gsl'
+ if class_variable_defined? gsl_available
+ class_variable_get(gsl_available)
+ else
+ begin
+ require 'gsl'
+ class_variable_set(gsl_available, true)
+ rescue LoadError
+ class_variable_set(gsl_available, false)
+ end
+ end
+ end
end
- create_has_library :gsl
end
diff --git a/lib/integration/methods.rb b/lib/integration/methods.rb
new file mode 100644
index 0000000..cc55e8a
--- /dev/null
+++ b/lib/integration/methods.rb
@@ -0,0 +1,394 @@
+class Integration
+ class << self
+
+ # Rectangle method
+ # +n+ implies number of subdivisions
+ # Source:
+ # * Ayres : Outline of calculus
+ def rectangle(t1, t2, n, &f)
+ d = (t2 - t1) / n.to_f
+ n.times.inject(0) do|ac, i|
+ ac + f[t1 + d * (i + 0.5)]
+ end * d
+ end
+
+ alias_method :midpoint, :rectangle
+
+ # Trapezoid method
+ # +n+ implies number of subdivisions
+ # Source:
+ # * Ayres : Outline of calculus
+ def trapezoid(t1, t2, n, &f)
+ d = (t2 - t1) / n.to_f
+ (d / 2.0) * (f[t1] + 2 * (1..(n - 1)).inject(0) do|ac, i|
+ ac + f[t1 + d * i]
+ end + f[t2])
+ end
+
+ # Simpson's rule
+ # +n+ implies number of subdivisions
+ # Source:
+ # * Ayres : Outline of calculus
+ def simpson(t1, t2, n, &f)
+ n += 1 unless n.even?
+ d = (t2 - t1) / n.to_f
+ out = (d / 3.0) * (f[t1.to_f].to_f + ((1..(n - 1)).inject(0) do|ac, i|
+ ac + ((i.even?) ? 2 : 4) * f[t1 + d * i]
+ end) + f[t2.to_f].to_f)
+ out
+ end
+
+ # Simpson's 3/8 Rule
+ # +n+ implies number of subdivisions
+ # Source:
+ # * Burden, Richard L. and Faires, J. Douglas (2000): Numerical Analysis (7th ed.). Brooks/Cole
+ def simpson3by8(t1, t2, n, &f)
+ d = (t2 - t1) / n.to_f
+ ac = 0
+ (0..n - 1).each do |i|
+ ac += (d / 8.0) * (f[t1 + i * d] + 3 * f[t1 + i * d + d / 3] + 3 * f[t1 + i * d + 2 * d / 3] + f[t1 + (i + 1) * d])
+ end
+ ac
+ end
+
+ # Boole's Rule
+ # +n+ implies number of subdivisions
+ # Source:
+ # Weisstein, Eric W. "Boole's Rule." From MathWorld—A Wolfram Web Resource
+ def boole(t1, t2, n, &f)
+ d = (t2 - t1) / n.to_f
+ ac = 0
+ (0..n - 1).each do |i|
+ ac += (d / 90.0) * (7 * f[t1 + i * d] + 32 * f[t1 + i * d + d / 4] + 12 * f[t1 + i * d + d / 2] + 32 * f[t1 + i * d + 3 * d / 4] + 7 * f[t1 + (i + 1) * d])
+ end
+ ac
+ end
+
+ # Open Trapezoid method
+ # +n+ implies number of subdivisions
+ # Values computed at mid point and end point instead of starting points
+ def open_trapezoid(t1, t2, n, &f)
+ d = (t2 - t1) / n.to_f
+ ac = 0
+ (0..n - 1).each do |i|
+ ac += (d / 2.0) * (f[t1 + i * d + d / 3] + f[t1 + i * d + 2 * d / 3])
+ end
+ ac
+ end
+
+ # Milne's Method
+ # +n+ implies number of subdivisions
+ # Source:
+ # Abramowitz, M. and Stegun, I. A. (Eds.).
+ # Handbook of Mathematical Functions with Formulas, Graphs, and Mathematical Tables,
+ # 9th printing. New York: Dover, pp. 896-897, 1972.
+ def milne(t1, t2, n, &f)
+ d = (t2 - t1) / n.to_f
+ ac = 0
+ (0..n - 1).each do |i|
+ ac += (d / 3.0) * (2 * f[t1 + i * d + d / 4] - f[t1 + i * d + d / 2] + 2 * f[t1 + i * d + 3 * d / 4])
+ end
+ ac
+ end
+
+ # Adaptive Quadrature
+ # Calls the Simpson's rule recursively on subintervals
+ # in case the error exceeds the desired tolerance
+ # +tolerance+ is the desired tolerance of error
+ def adaptive_quadrature(a, b, tolerance)
+ h = (b.to_f - a) / 2
+ fa = yield(a)
+ fc = yield(a + h)
+ fb = yield(b)
+ s = h * (fa + (4 * fc) + fb) / 3
+
+ helper = proc do |_a, _b, _fa, _fb, _fc, _h, _s, level|
+ if level < 1 / tolerance.to_f
+ fd = yield(_a + (_h / 2))
+ fe = yield(_a + (3 * (_h / 2)))
+ s1 = _h * (_fa + (4.0 * fd) + _fc) / 6
+ s2 = _h * (_fc + (4.0 * fe) + _fb) / 6
+ if ((s1 + s2) - _s).abs <= tolerance
+ s1 + s2
+ else
+ helper.call(_a, _a + _h, _fa, _fc, fd, _h / 2, s1, level + 1) +
+ helper.call(_a + _h, _b, _fc, _fb, fe, _h / 2, s2, level + 1)
+ end
+ else
+ fail 'Integral did not converge'
+ end
+
+ end
+ helper.call(a, b, fa, fb, fc, h, s, 1)
+ end
+
+ # Gaussian Quadrature
+ # n-point Gaussian quadrature rule gives an exact result for polynomials of degree 2n − 1 or less
+ def gauss(t1, t2, n)
+ case n
+ when 1
+ z = [0.0]
+ w = [2.0]
+ when 2
+ z = [-0.57735026919, 0.57735026919]
+ w = [1.0, 1.0]
+ when 3
+ z = [-0.774596669241, 0.0, 0.774596669241]
+ w = [0.555555555556, 0.888888888889, 0.555555555556]
+ when 4
+ z = [-0.861136311594, -0.339981043585, 0.339981043585, 0.861136311594]
+ w = [0.347854845137, 0.652145154863, 0.652145154863, 0.347854845137]
+ when 5
+ z = [-0.906179845939, -0.538469310106, 0.0, 0.538469310106, 0.906179845939]
+ w = [0.236926885056, 0.478628670499, 0.568888888889, 0.478628670499, 0.236926885056]
+ when 6
+ z = [-0.932469514203, -0.661209386466, -0.238619186083, 0.238619186083, 0.661209386466, 0.932469514203]
+ w = [0.171324492379, 0.360761573048, 0.467913934573, 0.467913934573, 0.360761573048, 0.171324492379]
+ when 7
+ z = [-0.949107912343, -0.741531185599, -0.405845151377, 0.0, 0.405845151377, 0.741531185599, 0.949107912343]
+ w = [0.129484966169, 0.279705391489, 0.381830050505, 0.417959183673, 0.381830050505, 0.279705391489, 0.129484966169]
+ when 8
+ z = [-0.960289856498, -0.796666477414, -0.525532409916, -0.183434642496, 0.183434642496, 0.525532409916, 0.796666477414, 0.960289856498]
+ w = [0.10122853629, 0.222381034453, 0.313706645878, 0.362683783378, 0.362683783378, 0.313706645878, 0.222381034453, 0.10122853629]
+ when 9
+ z = [-0.968160239508, -0.836031107327, -0.613371432701, -0.324253423404, 0.0, 0.324253423404, 0.613371432701, 0.836031107327, 0.968160239508]
+ w = [0.0812743883616, 0.180648160695, 0.260610696403, 0.31234707704, 0.330239355001, 0.31234707704, 0.260610696403, 0.180648160695, 0.0812743883616]
+ when 10
+ z = [-0.973906528517, -0.865063366689, -0.679409568299, -0.433395394129, -0.148874338982, 0.148874338982, 0.433395394129, 0.679409568299, 0.865063366689, 0.973906528517]
+ w = [0.0666713443087, 0.149451349151, 0.219086362516, 0.26926671931, 0.295524224715, 0.295524224715, 0.26926671931, 0.219086362516, 0.149451349151, 0.0666713443087]
+ else
+ fail "Invalid number of spaced abscissas #{n}, should be 1-10"
+ end
+
+ sum = 0
+ (0...n).each do |i|
+ t = ((t1.to_f + t2) / 2.0) + (((t2 - t1) / 2.0) * z[i])
+ sum += w[i] * yield(t)
+ end
+ ((t2 - t1) / 2.0) * sum
+ end
+
+ # Gauss Kronrod Rule:
+ # Provides a 3n+1 order estimate while re-using the function values of a lower-order(n order) estimate
+ # Source:
+ # "Gauss–Kronrod quadrature formula", Encyclopedia of Mathematics, Springer, ISBN 978-1-55608-010-4
+ def gauss_kronrod(t1, t2, n, points)
+ # g7k15
+ case points
+ when 15
+
+ z = [-0.9914553711208126, -0.9491079123427585, -0.8648644233597691,
+ -0.7415311855993945, -0.5860872354676911, -0.4058451513773972,
+ -0.20778495500789848, 0.0, 0.20778495500789848,
+ 0.4058451513773972, 0.5860872354676911, 0.7415311855993945,
+ 0.8648644233597691, 0.9491079123427585, 0.9914553711208126]
+
+ w = [0.022935322010529224, 0.06309209262997856, 0.10479001032225019,
+ 0.14065325971552592, 0.1690047266392679, 0.19035057806478542,
+ 0.20443294007529889, 0.20948214108472782, 0.20443294007529889,
+ 0.19035057806478542, 0.1690047266392679, 0.14065325971552592,
+ 0.10479001032225019, 0.06309209262997856, 0.022935322010529224]
+
+ when 21
+ # g10k21
+
+ z = [-0.9956571630258081, -0.9739065285171717, -0.9301574913557082,
+ -0.8650633666889845, -0.7808177265864169, -0.6794095682990244,
+ -0.5627571346686047, -0.4333953941292472, -0.2943928627014602,
+ -0.14887433898163122, 0.0, 0.14887433898163122,
+ 0.2943928627014602, 0.4333953941292472, 0.5627571346686047,
+ 0.6794095682990244, 0.7808177265864169, 0.8650633666889845,
+ 0.9301574913557082, 0.9739065285171717, 0.9956571630258081]
+
+ w = [0.011694638867371874, 0.032558162307964725,
+ 0.054755896574351995, 0.07503967481091996, 0.0931254545836976,
+ 0.10938715880229764, 0.12349197626206584, 0.13470921731147334,
+ 0.14277593857706009, 0.14773910490133849, 0.1494455540029169,
+ 0.14773910490133849, 0.14277593857706009, 0.13470921731147334,
+ 0.12349197626206584, 0.10938715880229764, 0.0931254545836976,
+ 0.07503967481091996, 0.054755896574351995, 0.032558162307964725,
+ 0.011694638867371874]
+
+ when 31
+ # g15k31
+
+ z = [-0.9980022986933971, -0.9879925180204854, -0.9677390756791391,
+ -0.937273392400706, -0.8972645323440819, -0.8482065834104272,
+ -0.790418501442466, -0.7244177313601701, -0.650996741297417,
+ -0.5709721726085388, -0.4850818636402397, -0.3941513470775634,
+ -0.29918000715316884, -0.20119409399743451, -0.1011420669187175,
+ 0.0, 0.1011420669187175, 0.20119409399743451,
+ 0.29918000715316884, 0.3941513470775634, 0.4850818636402397,
+ 0.5709721726085388, 0.650996741297417, 0.7244177313601701,
+ 0.790418501442466, 0.8482065834104272, 0.8972645323440819,
+ 0.937273392400706, 0.9677390756791391, 0.9879925180204854,
+ 0.9980022986933971]
+
+ w = [0.005377479872923349, 0.015007947329316122, 0.02546084732671532,
+ 0.03534636079137585, 0.04458975132476488, 0.05348152469092809,
+ 0.06200956780067064, 0.06985412131872826, 0.07684968075772038,
+ 0.08308050282313302, 0.08856444305621176, 0.09312659817082532,
+ 0.09664272698362368, 0.09917359872179196, 0.10076984552387559,
+ 0.10133000701479154, 0.10076984552387559, 0.09917359872179196,
+ 0.09664272698362368, 0.09312659817082532, 0.08856444305621176,
+ 0.08308050282313302, 0.07684968075772038, 0.06985412131872826,
+ 0.06200956780067064, 0.05348152469092809, 0.04458975132476488,
+ 0.03534636079137585, 0.02546084732671532, 0.015007947329316122,
+ 0.005377479872923349]
+
+ when 41
+ # g20k41
+
+ z = [-0.9988590315882777, -0.9931285991850949, -0.9815078774502503,
+ -0.9639719272779138, -0.9408226338317548, -0.912234428251326,
+ -0.878276811252282, -0.8391169718222188, -0.7950414288375512,
+ -0.7463319064601508, -0.6932376563347514, -0.636053680726515,
+ -0.5751404468197103, -0.5108670019508271, -0.4435931752387251,
+ -0.37370608871541955, -0.301627868114913, -0.22778585114164507,
+ -0.15260546524092267, -0.07652652113349734, 0.0,
+ 0.07652652113349734, 0.15260546524092267, 0.22778585114164507,
+ 0.301627868114913, 0.37370608871541955, 0.4435931752387251,
+ 0.5108670019508271, 0.5751404468197103, 0.636053680726515,
+ 0.6932376563347514, 0.7463319064601508, 0.7950414288375512,
+ 0.8391169718222188, 0.878276811252282, 0.912234428251326,
+ 0.9408226338317548, 0.9639719272779138, 0.9815078774502503,
+ 0.9931285991850949, 0.9988590315882777]
+
+ w = [0.0030735837185205317, 0.008600269855642943,
+ 0.014626169256971253, 0.020388373461266523, 0.02588213360495116,
+ 0.0312873067770328, 0.036600169758200796, 0.041668873327973685,
+ 0.04643482186749767, 0.05094457392372869, 0.05519510534828599,
+ 0.05911140088063957, 0.06265323755478117, 0.06583459713361842,
+ 0.06864867292852161, 0.07105442355344407, 0.07303069033278667,
+ 0.07458287540049918, 0.07570449768455667, 0.07637786767208074,
+ 0.07660071191799965, 0.07637786767208074, 0.07570449768455667,
+ 0.07458287540049918, 0.07303069033278667, 0.07105442355344407,
+ 0.06864867292852161, 0.06583459713361842, 0.06265323755478117,
+ 0.05911140088063957, 0.05519510534828599, 0.05094457392372869,
+ 0.04643482186749767, 0.041668873327973685, 0.036600169758200796,
+ 0.0312873067770328, 0.02588213360495116, 0.020388373461266523,
+ 0.014626169256971253, 0.008600269855642943,
+ 0.0030735837185205317]
+
+ when 61
+ # g30k61
+
+ z = [-0.9994844100504906, -0.9968934840746495, -0.9916309968704046,
+ -0.9836681232797472, -0.9731163225011262, -0.9600218649683075,
+ -0.94437444474856, -0.9262000474292743, -0.9055733076999078,
+ -0.8825605357920527, -0.8572052335460612, -0.8295657623827684,
+ -0.799727835821839, -0.7677774321048262, -0.7337900624532268,
+ -0.6978504947933158, -0.6600610641266269, -0.6205261829892429,
+ -0.5793452358263617, -0.5366241481420199, -0.49248046786177857,
+ -0.44703376953808915, -0.4004012548303944, -0.3527047255308781,
+ -0.30407320227362505, -0.25463692616788985,
+ -0.20452511668230988, -0.15386991360858354,
+ -0.10280693796673702, -0.0514718425553177, 0.0,
+ 0.0514718425553177, 0.10280693796673702, 0.15386991360858354,
+ 0.20452511668230988, 0.25463692616788985, 0.30407320227362505,
+ 0.3527047255308781, 0.4004012548303944, 0.44703376953808915,
+ 0.49248046786177857, 0.5366241481420199, 0.5793452358263617,
+ 0.6205261829892429, 0.6600610641266269, 0.6978504947933158,
+ 0.7337900624532268, 0.7677774321048262, 0.799727835821839,
+ 0.8295657623827684, 0.8572052335460612, 0.8825605357920527,
+ 0.9055733076999078, 0.9262000474292743, 0.94437444474856,
+ 0.9600218649683075, 0.9731163225011262, 0.9836681232797472,
+ 0.9916309968704046, 0.9968934840746495, 0.9994844100504906]
+
+ w = [0.0013890136986770077, 0.003890461127099884,
+ 0.0066307039159312926, 0.009273279659517764,
+ 0.011823015253496341, 0.014369729507045804, 0.01692088918905327,
+ 0.019414141193942382, 0.021828035821609193, 0.0241911620780806,
+ 0.0265099548823331, 0.02875404876504129, 0.030907257562387762,
+ 0.03298144705748372, 0.034979338028060025, 0.03688236465182123,
+ 0.038678945624727595, 0.040374538951535956,
+ 0.041969810215164244, 0.04345253970135607, 0.04481480013316266,
+ 0.04605923827100699, 0.04718554656929915, 0.04818586175708713,
+ 0.04905543455502978, 0.04979568342707421, 0.05040592140278235,
+ 0.05088179589874961, 0.051221547849258774, 0.05142612853745902,
+ 0.05149472942945157, 0.05142612853745902, 0.051221547849258774,
+ 0.05088179589874961, 0.05040592140278235, 0.04979568342707421,
+ 0.04905543455502978, 0.04818586175708713, 0.04718554656929915,
+ 0.04605923827100699, 0.04481480013316266, 0.04345253970135607,
+ 0.041969810215164244, 0.040374538951535956,
+ 0.038678945624727595, 0.03688236465182123, 0.034979338028060025,
+ 0.03298144705748372, 0.030907257562387762, 0.02875404876504129,
+ 0.0265099548823331, 0.0241911620780806, 0.021828035821609193,
+ 0.019414141193942382, 0.01692088918905327, 0.014369729507045804,
+ 0.011823015253496341, 0.009273279659517764,
+ 0.0066307039159312926, 0.003890461127099884,
+ 0.0013890136986770077]
+
+ else # using 15 point quadrature
+
+ n = 15
+
+ z = [-0.9914553711208126, -0.9491079123427585, -0.8648644233597691,
+ -0.7415311855993945, -0.5860872354676911, -0.4058451513773972,
+ -0.20778495500789848, 0.0, 0.20778495500789848,
+ 0.4058451513773972, 0.5860872354676911, 0.7415311855993945,
+ 0.8648644233597691, 0.9491079123427585, 0.9914553711208126]
+
+ w = [0.022935322010529224, 0.06309209262997856, 0.10479001032225019,
+ 0.14065325971552592, 0.1690047266392679, 0.19035057806478542,
+ 0.20443294007529889, 0.20948214108472782, 0.20443294007529889,
+ 0.19035057806478542, 0.1690047266392679, 0.14065325971552592,
+ 0.10479001032225019, 0.06309209262997856, 0.022935322010529224]
+
+ end
+
+ sum = 0
+ (0...n).each do |i|
+ t = ((t1.to_f + t2) / 2.0) + (((t2 - t1) / 2.0) * z[i])
+ sum += w[i] * yield(t)
+ end
+
+ ((t2 - t1) / 2.0) * sum
+ end
+
+ # Romberg Method:
+ # It is obtained by applying extrapolation techniques repeatedly on the trapezoidal rule
+ def romberg(a, b, tolerance, max_iter = 20)
+ # NOTE one-based arrays are used for convenience
+ h = b.to_f - a
+ close = 1
+ r = [[(h / 2) * (yield(a) + yield(b))]]
+ j = 0
+ hn = ->(n) { h / (2**n) }
+ while j <= max_iter && tolerance < close
+ j += 1
+ r.push((j + 1).times.map { [] })
+ ul = 2**(j - 1)
+ r[j][0] = r[j - 1][0] / 2.0 + hn[j] * (1..ul).inject(0) { |ac, k| ac + yield(a + (2 * k - 1) * hn[j]) }
+ (1..j).each do |k|
+ r[j][k] = ((4**k) * r[j][k - 1] - r[j - 1][k - 1]) / ((4**k) - 1)
+ end
+ close = (r[j][j] - r[j - 1][j - 1])
+ end
+ r[j][j]
+ end
+
+ # Monte Carlo
+ #
+ # Uses a non-deterministic approach for calculation of definite integrals.
+ # Estimates the integral by randomly choosing points in a set and then
+ # calculating the number of points that fall in the desired area.
+ def monte_carlo(t1, t2, n)
+ width = (t2 - t1).to_f
+ height = nil
+ vals = []
+ n.times do
+ t = t1 + (rand * width)
+ ft = yield(t)
+ height = ft if height.nil? || ft > height
+ vals << ft
+ end
+ area_ratio = 0
+ vals.each do |ft|
+ area_ratio += (ft / height.to_f) / n.to_f
+ end
+ (width * height) * area_ratio
+ end
+
+ end
+end
diff --git a/lib/integration/version.rb b/lib/integration/version.rb
new file mode 100644
index 0000000..8347671
--- /dev/null
+++ b/lib/integration/version.rb
@@ -0,0 +1,3 @@
+class Integration
+ VERSION = '0.1.4'
+end
diff --git a/lib/opencl/Makefile b/lib/opencl/Makefile
new file mode 100644
index 0000000..3d61108
--- /dev/null
+++ b/lib/opencl/Makefile
@@ -0,0 +1,29 @@
+all: cl.so
+
+CC=gcc
+CL_HEADERS_PATH=
+LIBOPENCL_PATH=
+
+
+UNAME := $(shell uname)
+ifeq ($(UNAME), Linux)
+# do something Linux-y
+OPENCL_LIBRARY_CALL=-lOpenCL
+endif
+ifeq ($(UNAME), Solaris)
+# do something Solaris-y
+OPENCL_LIBRARY_CALL=-framework OpenCL
+endif
+
+
+
+cl.so: integration_host.o
+ $(CC) -shared -o cl.so integration_host.o -I $(CL_HEADERS_PATH) -L $(LIBOPENCL_PATH) $(OPENCL_LIBRARY_CALL)
+
+
+integration_host.o: integration_host.c
+ $(CC) -fpic -c integration_host.c
+
+clean:
+ rm cl.so integration_host.o
+
diff --git a/lib/opencl/integration_host.c b/lib/opencl/integration_host.c
new file mode 100644
index 0000000..225d3a8
--- /dev/null
+++ b/lib/opencl/integration_host.c
@@ -0,0 +1,151 @@
+// This file contains the host code of the openCL supported integration
+#include <stdio.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdlib.h>
+#include <limits.h> //For PATH_MAX
+
+// import OpenCL headers assuming OS is a linux version or MAC
+#ifdef __APPLE__
+ #include<OpenCL/opencl.h>
+#else
+ #include<CL/cl.h>
+#endif
+
+#define MAX_SOURCE_SIZE (0x100000) // maximum size allowed for the kernel text
+
+// these are the available integration methods
+enum methods{
+ rectangle,
+ trapezoid,
+ simpson,
+ adaptive_quadrature,
+ gauss,
+ romberg,
+ monte_carlo
+};
+
+double opencl_integration(double lower, double upper, int n, char* f,
+ enum methods method, char* path_to_kerne) {
+
+ char* source_str;
+ size_t source_size;
+ int i = 0;
+ double dx = (upper - lower) / n;
+ double *results = (double*) malloc(n * sizeof(double));
+
+ // read the corresponding kernel
+ FILE* fp;
+ sprintf(path_to_kerne, "%s%s", path_to_kerne, "/unidimensional_kernel.cl");
+ fp = fopen(path_to_kerne, "r");
+
+ // if the kernel file doesn't exist, stop the execution
+ if(fp == 0) {
+ printf("kernel file not found\n");
+ exit(0);
+ }
+
+ char *temp_source;
+ // allocate memory for kenel code
+ temp_source = (char*) malloc(sizeof(char) * MAX_SOURCE_SIZE);
+ source_str = (char*) malloc(sizeof(char) * MAX_SOURCE_SIZE);
+
+ temp_source[0] = '\0'; // make temp_source a null string
+ char line[100];
+ // read the text of the kernel into temp_source
+ while(!feof(fp)) {
+ if (fgets(line, 100, fp)) {
+ sprintf(temp_source, "%s%s",temp_source, line);
+ }
+ }
+
+ // create the complete kernel code appending,
+ // f() - integrating function
+ sprintf(source_str, "double f(double x){return (%s);}\n%s", f, temp_source);
+
+ // printf("\nfunction----------------------------\n%s\n--------------------------\n", source_str);
+ source_size = strlen(source_str);
+ fclose(fp);
+ free(temp_source);
+
+ cl_platform_id platform_id = NULL;
+ cl_device_id device_id = NULL;
+ cl_uint ret_num_devices;
+ cl_uint ret_num_platforms;
+ cl_int ret;
+ ret = clGetPlatformIDs(1, &platform_id, &ret_num_platforms);
+ // CL_DEVICE_TYPE_CPU is being used currently as the testing value
+ ret = clGetDeviceIDs( platform_id, CL_DEVICE_TYPE_CPU, 1, &device_id, &ret_num_devices);
+
+ // create kernel
+ cl_context context = clCreateContext( NULL, 1, &device_id, NULL, NULL, &ret);
+ // create command queue
+ cl_command_queue command_queue = clCreateCommandQueue(context, device_id, 0, &ret);
+
+ // create memory buffers to share memory with kernel program
+ cl_mem lower_obj = clCreateBuffer(context, CL_MEM_READ_ONLY, sizeof(double) , NULL, &ret);
+ cl_mem dx_obj = clCreateBuffer(context, CL_MEM_READ_ONLY, sizeof(double) , NULL, &ret);
+ cl_mem n_obj = clCreateBuffer(context, CL_MEM_READ_ONLY, sizeof(int) , NULL, &ret);
+ cl_mem method_obj = clCreateBuffer(context, CL_MEM_READ_ONLY, sizeof(int) , NULL, &ret);
+ cl_mem result_obj = clCreateBuffer(context, CL_MEM_WRITE_ONLY, sizeof(double) * n , NULL, &ret);
+ //cl_mem epsilon_obj = clCreateBuffer(context, CL_MEM_READ_ONLY, sizeof(double) , NULL, &ret);
+ //cl_mem golden_obj = clCreateBuffer(context, CL_MEM_READ_ONLY, sizeof(double) , NULL, &ret);
+
+ // writes the input values into the allocated memory buffers
+ ret = clEnqueueWriteBuffer(command_queue, lower_obj, CL_TRUE, 0, sizeof(double) , &lower , 0, NULL, NULL);
+ ret = clEnqueueWriteBuffer(command_queue, dx_obj , CL_TRUE, 0, sizeof(double) , &dx , 0, NULL, NULL);
+ ret = clEnqueueWriteBuffer(command_queue, n_obj , CL_TRUE, 0, sizeof(int) , &n , 0, NULL, NULL);
+ ret = clEnqueueWriteBuffer(command_queue, method_obj, CL_TRUE, 0, sizeof(int) , &method, 0, NULL, NULL);
+ //ret = clEnqueueWriteBuffer(command_queue, epsilon_obj , CL_TRUE, 0, sizeof(double) , &epsilon , 0, NULL, NULL);
+ //ret = clEnqueueWriteBuffer(command_queue, golden_obj , CL_TRUE, 0, sizeof(double) , &golden , 0, NULL, NULL);
+
+ // create kernel program
+ cl_program program = clCreateProgramWithSource(context, 1, (const char **)&source_str, (const size_t *)&source_size, &ret);
+ // build the kernel program. Still the code isn't being executed
+ // memory buffers haven't involved. Any error at this stage MAY be a syntax error of kernel code
+ ret = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL);
+ // this gives error message only if the kernel code includes any syntax error
+ if(ret == CL_BUILD_PROGRAM_FAILURE) printf("\nerror while building kernel: %d\n", ret);
+ // create the kernel calling the kernel function 'minimize'
+ cl_kernel kernel = clCreateKernel(program, "integrate", &ret);
+
+ // set arguments of kernel function
+ ret = clSetKernelArg(kernel, 0 , sizeof(cl_mem) , (void *)&lower_obj);
+ ret = clSetKernelArg(kernel, 1 , sizeof(cl_mem) , (void *)&dx_obj);
+ ret = clSetKernelArg(kernel, 2 , sizeof(cl_mem) , (void *)&n_obj);
+ ret = clSetKernelArg(kernel, 3 , sizeof(cl_mem) , (void *)&method_obj);
+ ret = clSetKernelArg(kernel, 4 , sizeof(cl_mem) * n, (void *)&result_obj);
+ //ret = clSetKernelArg(kernel, 9 , sizeof(cl_mem) , (void *)&epsilon_obj);
+ //ret = clSetKernelArg(kernel, 10, sizeof(cl_mem) , (void *)&golden_obj);
+
+ size_t global_item_size = n;
+ // enqueue the jobs and let them to be solved by kernel program
+ ret = clEnqueueNDRangeKernel(command_queue, kernel, 1, NULL, &global_item_size, NULL, 0, NULL, NULL);
+
+ // retrieve results from the shared memory buffers
+ ret = clEnqueueReadBuffer(command_queue, result_obj, CL_TRUE, 0, sizeof(double) * n, results, 0, NULL, NULL);
+
+ // clear the allocated memory
+ ret = clFlush(command_queue);
+ ret = clFinish(command_queue);
+ ret = clReleaseKernel(kernel);
+ ret = clReleaseProgram(program);
+
+ ret = clReleaseMemObject(lower_obj);
+ ret = clReleaseMemObject(dx_obj);
+ ret = clReleaseMemObject(n_obj);
+ ret = clReleaseMemObject(method_obj);
+ //ret = clReleaseMemObject(epsilon_obj);
+ //ret = clReleaseMemObject(golden_obj);
+
+ ret = clReleaseCommandQueue(command_queue);
+ ret = clReleaseContext(context);
+ free(source_str);
+
+ double final_result = 0;
+ for(i = 0; i < n; ++i) {
+ final_result += results[i];
+ }
+
+ return final_result;
+}
diff --git a/lib/opencl/opencl_minimization.rb b/lib/opencl/opencl_minimization.rb
new file mode 100644
index 0000000..28517ee
--- /dev/null
+++ b/lib/opencl/opencl_minimization.rb
@@ -0,0 +1,251 @@
+require 'ffi'
+
+module OpenCLMinimization extend FFI::Library
+
+ MAX_ITERATIONS_DEFAULT = 100000
+ EPSILON_DEFAULT = 0.00001
+ GOLDEN_DEFAULT = 0.3819660
+ SQRT_EPSILON_DEFAULT = 0.00001
+ PATH_TO_KERNEL = File.expand_path(File.dirname(__FILE__))
+
+ ffi_lib "#{File.expand_path(File.dirname(__FILE__))}/cl.so"
+
+ # attack with the opencl_minimize of min_host.c
+ attach_function 'opencl_minimize', [:int, :pointer, :pointer, :pointer, :int, :string, :string,
+ :string, :pointer, :pointer, :int, :int, :float, :float, :float, :string], :void
+
+ # Classic GodlSectionMinimizer minimization method.
+ # Basic minimization algorithm. Slow, but robust.
+ # See Unidimensional for methods.
+ # == Usage
+ # n = 3
+ # start_point = [1, 3, 5]
+ # expected_point = [1.5, 3.5, 5.5]
+ # end_point = [3, 5, 7]
+ # f = "pow((x-2)*(x-4)*(x-6), 2)+1"
+ # min = OpenCLMinimization::GodlSectionMinimizer.new(n, start_point, expected_point, end_point, f)
+ # min.minimize
+ # min.x_minimum
+ # min.f_minimum
+ #
+ class GodlSectionMinimizer
+ attr_reader :x_minimum
+ attr_reader :f_minimum
+
+ attr_writer :max_iterations
+ attr_writer :epsilon
+ attr_writer :golden
+
+ # == Parameters:
+ # * <tt>n</tt>: Number of Jobs
+ # * <tt>start_point</tt>: Lower possible value
+ # * <tt>expected_point</tt>: Initial point
+ # * <tt>end_point</tt>: Higher possible value
+ # * <tt>f</tt>: Original function string
+ #
+ def initialize(n, start_point, expected_point, end_point, f)
+ @n = n
+ @start_point = start_point
+ @expected_point = expected_point
+ @end_point = end_point
+ @f = f
+ @max_iterations = MAX_ITERATIONS_DEFAULT
+ @epsilon = EPSILON_DEFAULT
+ @golden = GOLDEN_DEFAULT
+ @sqrt_epsilon = SQRT_EPSILON_DEFAULT
+ end
+
+ def minimize
+ # create Buffers for inputs and outputs
+ start_buffer = FFI::Buffer.alloc_inout(:pointer, @n)
+ expected_buffer = FFI::Buffer.alloc_inout(:pointer, @n)
+ end_buffer = FFI::Buffer.alloc_inout(:pointer, @n)
+ x_buffer = FFI::Buffer.alloc_inout(:pointer, @n)
+ f_buffer = FFI::Buffer.alloc_inout(:pointer, @n)
+
+ # set inputs
+ start_buffer.write_array_of_float(@start_point)
+ expected_buffer.write_array_of_float(@expected_point)
+ end_buffer.write_array_of_float(@end_point)
+
+ # call minimizer
+ OpenCLMinimization::opencl_minimize(@n, start_buffer, expected_buffer, end_buffer, 0, @f, "", "", x_buffer,
+ f_buffer, 0, @max_iterations, @epsilon, @golden, @sqrt_epsilon, PATH_TO_KERNEL)
+
+ @x_minimum = Array.new(@n)
+ @f_minimum = Array.new(@n)
+ # read results
+ @x_minimum = x_buffer.read_array_of_float(@n)
+ @f_minimum = f_buffer.read_array_of_float(@n)
+ end
+ end
+
+ # Classic Newton-Raphson minimization method.
+ # Requires first and second derivative
+ # == Usage
+ # n = 3
+ # expected_point = [1, 100, 1000]
+ # f = "(x-3)*(x-3)+5"
+ # fd = "2*(x-3)"
+ # fdd = "2"
+ # min = OpenCLMinimization::NewtonRampsonMinimizer.new(n, expected_point, f, fd, fdd)
+ # min.minimize
+ # min.x_minimum
+ # min.f_minimum
+ #
+ class NewtonRampsonMinimizer
+ attr_reader :x_minimum
+ attr_reader :f_minimum
+
+ attr_writer :max_iterations
+ attr_writer :epsilon
+ attr_writer :golden
+
+ # == Parameters:
+ # * <tt>n</tt>: Number of Jobs
+ # * <tt>expected_point</tt>: Initial point
+ # * <tt>f</tt>: Original function
+ # * <tt>fd</tt>: First derivative function string
+ # * <tt>fdd</tt>: Second derivative function string
+ #
+ def initialize(n, expected_point, f, fd, fdd)
+ @n = n
+ @expected_point = expected_point
+ @f = f
+ @fd = fd
+ @fdd = fdd
+ @max_iterations = MAX_ITERATIONS_DEFAULT
+ @epsilon = EPSILON_DEFAULT
+ @golden = GOLDEN_DEFAULT
+ @sqrt_epsilon = SQRT_EPSILON_DEFAULT
+ end
+
+ def minimize
+ # create Buffers for inputs and outputs
+ expected_buffer = FFI::Buffer.alloc_inout(:pointer, @n)
+ x_buffer = FFI::Buffer.alloc_inout(:pointer, @n)
+ f_buffer = FFI::Buffer.alloc_inout(:pointer, @n)
+
+ # set inputs
+ expected_buffer.write_array_of_float(@expected_point)
+
+ # call minimizer
+ OpenCLMinimization::opencl_minimize(@n, nil, expected_buffer, nil, 1, @f, @fd, @fdd, x_buffer, f_buffer, 0,
+ @max_iterations, @epsilon, @golden, @sqrt_epsilon, PATH_TO_KERNEL)
+
+ @x_minimum = Array.new(@n)
+ @f_minimum = Array.new(@n)
+ # read results
+ @x_minimum = x_buffer.read_array_of_float(@n)
+ @f_minimum = f_buffer.read_array_of_float(@n)
+ end
+ end
+
+ # = Bisection Minimizer.
+ # Basic minimization algorithm. Slow, but robust.
+ # See Unidimensional for methods.
+ # == Usage.
+ # n = 3
+ # start_point = [1, 3, 5]
+ # expected_point = [1.5, 3.5, 5.5]
+ # end_point = [3, 5, 7]
+ # f = "pow((x-2)*(x-4)*(x-6), 2)+1"
+ # min = OpenCLMinimization::BisectionMinimizer.new(n, start_point, expected_point, end_point, f)
+ # min.minimize
+ # min.x_minimum
+ # min.f_minimum
+ #
+ class BisectionMinimizer < GodlSectionMinimizer
+
+ def minimize
+ # create Buffers for inputs and outputs
+ start_buffer = FFI::Buffer.alloc_inout(:pointer, @n)
+ expected_buffer = FFI::Buffer.alloc_inout(:pointer, @n)
+ end_buffer = FFI::Buffer.alloc_inout(:pointer, @n)
+ x_buffer = FFI::Buffer.alloc_inout(:pointer, @n)
+ f_buffer = FFI::Buffer.alloc_inout(:pointer, @n)
+
+ # set inputs
+ start_buffer.write_array_of_float(@start_point)
+ expected_buffer.write_array_of_float(@expected_point)
+ end_buffer.write_array_of_float(@end_point)
+
+ # call minimizer
+ OpenCLMinimization::opencl_minimize(@n, start_buffer, expected_buffer, end_buffer, 2, @f, "", "", x_buffer,
+ f_buffer, 0, @max_iterations, @epsilon, @golden, @sqrt_epsilon, PATH_TO_KERNEL)
+
+ @x_minimum = Array.new(@n)
+ @f_minimum = Array.new(@n)
+ # read results
+ @x_minimum = x_buffer.read_array_of_float(@n)
+ @f_minimum = f_buffer.read_array_of_float(@n)
+ end
+ end
+
+ # Direct port of Brent algorithm found on GSL.
+ # See Unidimensional for methods.
+ # == Usage
+ # n = 3
+ # start_point = [1, 3, 5]
+ # expected_point = [1.5, 3.5, 5.5]
+ # end_point = [3, 5, 7]
+ # f = "pow((x-2)*(x-4)*(x-6), 2)+1"
+ # min = OpenCLMinimization::BisectionMinimizer.new(n, start_point, expected_point, end_point, f)
+ # min.minimize
+ # min.x_minimum
+ # min.f_minimum
+ #
+ class BrentMinimizer
+ attr_reader :x_minimum
+ attr_reader :f_minimum
+
+ attr_writer :max_iterations
+ attr_writer :epsilon
+ attr_writer :golden
+ attr_writer :sqrt_epsilon
+
+ # == Parameters:
+ # * <tt>n</tt>: Number of Jobs
+ # * <tt>start_point</tt>: Lower possible value
+ # * <tt>expected_point</tt>: Initial point
+ # * <tt>end_point</tt>: Higher possible value
+ # * <tt>f</tt>: Original function string
+ #
+ def initialize(n, start_point, expected_point, end_point, f)
+ @n = n
+ @start_point = start_point
+ @expected_point = expected_point
+ @end_point = end_point
+ @f = f
+ @max_iterations = MAX_ITERATIONS_DEFAULT
+ @epsilon = EPSILON_DEFAULT
+ @golden = GOLDEN_DEFAULT
+ @sqrt_epsilon = SQRT_EPSILON_DEFAULT
+ end
+
+ def minimize
+ # create Buffers for inputs and outputs
+ start_buffer = FFI::Buffer.alloc_inout(:pointer, @n)
+ expected_buffer = FFI::Buffer.alloc_inout(:pointer, @n)
+ end_buffer = FFI::Buffer.alloc_inout(:pointer, @n)
+ x_buffer = FFI::Buffer.alloc_inout(:pointer, @n)
+ f_buffer = FFI::Buffer.alloc_inout(:pointer, @n)
+
+ # set inputs
+ start_buffer.write_array_of_float(@start_point)
+ expected_buffer.write_array_of_float(@expected_point)
+ end_buffer.write_array_of_float(@end_point)
+
+ # call minimizer
+ OpenCLMinimization::opencl_minimize(@n, start_buffer, expected_buffer, end_buffer, 3, @f, "", "", x_buffer,
+ f_buffer, 0, @max_iterations, @epsilon, @golden, @sqrt_epsilon, PATH_TO_KERNEL)
+
+ @x_minimum = Array.new(@n)
+ @f_minimum = Array.new(@n)
+ # read results
+ @x_minimum = x_buffer.read_array_of_float(@n)
+ @f_minimum = f_buffer.read_array_of_float(@n)
+ end
+ end
+
+end
diff --git a/lib/opencl/unidimensional_kernel.cl b/lib/opencl/unidimensional_kernel.cl
new file mode 100644
index 0000000..a2ecb58
--- /dev/null
+++ b/lib/opencl/unidimensional_kernel.cl
@@ -0,0 +1,47 @@
+// This is the kenel code for unidimensional integration methods.
+// This is loaded into memory at runtime and a functions will be appended at run time,
+// double f(double x) - integrating function
+
+
+double rectangle(int i, double a, double dx);
+double trapezoid(int i, double a, double dx);
+double simpson(int i, double a, double dx);
+double romberg(int i, double a, double dx);
+
+__kernel void integrate(__global const double *a, __global const double *dx, __global const double *n,
+ __global int *method, __global double *results) {
+
+ // Get the index of the current element to be processed
+ int i = get_global_id(0);
+
+ // Do the operation
+ if(i <= n) {
+ int m = *method;
+ switch(m) {
+ case 0: results[i] = rectangle(i, *a, *dx);
+ break;
+ case 1: results[i] = trapezoid(i, *a, *dx);
+ break;
+ case 2: results[i] = simpson(i, *a, *dx);
+ break;
+ case 3: results[i] = romberg(i, *a, *dx);
+ break;
+ }
+ }
+}
+
+double rectangle(int i, double a, double dx) {
+ double midpoint = a + (i + 0.5) * dx;
+ return dx * f(midpoint);
+}
+
+double trapezoid(int i, double a, double dx) {
+ double lower = a + i * dx;
+ return (0.5 * dx * (f(lower) + f(lower + dx)));
+}
+
+double simpson(int i, double a, double dx) {
+ double lower = a + i * dx;
+ return (dx / 6) * (f(lower) + 4 * f(lower + 0.5 * dx) + f(lower + dx));
+}
+
diff --git a/metadata.gz.sig b/metadata.gz.sig
deleted file mode 100644
index b3a731c..0000000
--- a/metadata.gz.sig
+++ /dev/null
@@ -1 +0,0 @@
-�mV
݈5�H
�Ȗ�279s�Z�Q�eY�ڇ&����9CKy��*�p�����z�"��m�<��
��/��_��[!�6��a$mzj6`��Z���0��
6��S
xE��yn^+���y�(L�"o<�!
E]��\
g����6��(y�
.��>]��Xt�c���;ZS�()��@CG���t�>�t��{�snĆWW���hz��"/�ն!�� �w�y^����Y/�J��.���9��Ӛ�ջ"m��5�����w^��V�
\ No newline at end of file
diff --git a/metadata.yml b/metadata.yml
index 233422c..d4146de 100644
--- a/metadata.yml
+++ b/metadata.yml
@@ -1,124 +1,131 @@
---- !ruby/object:Gem::Specification
+--- !ruby/object:Gem::Specification
name: integration
-version: !ruby/object:Gem::Version
- prerelease:
- version: 0.1.0
+version: !ruby/object:Gem::Version
+ version: 0.1.4
platform: ruby
-authors:
-- Ben Gimpert
+authors:
- Claudio Bustos
+- Ben Gimpert
autorequire:
bindir: bin
-cert_chain:
-- |
- -----BEGIN CERTIFICATE-----
- MIIDMjCCAhqgAwIBAgIBADANBgkqhkiG9w0BAQUFADA/MREwDwYDVQQDDAhjbGJ1
- c3RvczEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPyLGQBGRYDY29t
- MB4XDTEwMDMyOTIxMzg1NVoXDTExMDMyOTIxMzg1NVowPzERMA8GA1UEAwwIY2xi
- dXN0b3MxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixkARkWA2Nv
- bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf8JVMGqE7m5kYb+PNN
- neZv2pcXV5fQCi6xkyG8bi2/SIFy/LyxuvLzEeOxBeaz1Be93bayIUquOIqw3dyw
- /KXWa31FxuNuvAm6CN8fyeRYX/ou4cw3OIUUnIvB7RMNIu4wbgeM6htV/QEsNLrv
- at1/mh9JpqawPrcjIOVMj4BIp67vmzJCaUf+S/H2uYtSO09F+YQE3tv85TPeRmqU
- yjyXyTc/oJiw1cXskUL8UtMWZmrwNLHXuZWWIMzkjiz3UNdhJr/t5ROk8S2WPznl
- 0bMy/PMIlAbqWolRn1zl2VFJ3TaXScbqImY8Wf4g62b/1ZSUlGrtnLNsCYXrWiso
- UPUCAwEAAaM5MDcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFGu9
- rrJ1H64qRmNNu3Jj/Qjvh0u5MA0GCSqGSIb3DQEBBQUAA4IBAQCV0Unka5isrhZk
- GjqSDqY/6hF+G2pbFcbWUpjmC8NWtAxeC+7NGV3ljd0e1SLfoyBj4gnFtFmY8qX4
- K02tgSZM0eDV8TpgFpWXzK6LzHvoanuahHLZEtk/+Z885lFene+nHadkem1n9iAB
- cs96JO9/JfFyuXM27wFAwmfHCmJfPF09R4VvGHRAvb8MGzSVgk2i06OJTqkBTwvv
- JHJdoyw3+8bw9RJ+jLaNoQ+xu+1pQdS2bb3m7xjZpufml/m8zFCtjYM/7qgkKR8z
- /ZZt8lCiKfFArppRrZayE2FVsps4X6WwBdrKTMZ0CKSXTRctbEj1BAZ67eoTvBBt
- rpP0jjs0
- -----END CERTIFICATE-----
-
-date: 2011-08-24 00:00:00 -03:00
-default_executable:
-dependencies:
-- !ruby/object:Gem::Dependency
- name: rspec
+cert_chain: []
+date: 2015-05-24 00:00:00.000000000 Z
+dependencies:
+- !ruby/object:Gem::Dependency
+ name: text-table
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
+ - - "~>"
+ - !ruby/object:Gem::Version
+ version: '1.2'
+ type: :runtime
prerelease: false
- requirement: &id001 !ruby/object:Gem::Requirement
- none: false
- requirements:
+ version_requirements: !ruby/object:Gem::Requirement
+ requirements:
+ - - "~>"
+ - !ruby/object:Gem::Version
+ version: '1.2'
+- !ruby/object:Gem::Dependency
+ name: bundler
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
- - ">="
- - !ruby/object:Gem::Version
- version: "2.0"
+ - !ruby/object:Gem::Version
+ version: 1.3.0
+ - - "<"
+ - !ruby/object:Gem::Version
+ version: '2.0'
type: :development
- version_requirements: *id001
-- !ruby/object:Gem::Dependency
- name: rubyforge
prerelease: false
- requirement: &id002 !ruby/object:Gem::Requirement
- none: false
- requirements:
+ version_requirements: !ruby/object:Gem::Requirement
+ requirements:
- - ">="
- - !ruby/object:Gem::Version
- version: "0"
+ - !ruby/object:Gem::Version
+ version: 1.3.0
+ - - "<"
+ - !ruby/object:Gem::Version
+ version: '2.0'
+- !ruby/object:Gem::Dependency
+ name: rake
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
+ - - "~>"
+ - !ruby/object:Gem::Version
+ version: '10.4'
type: :development
- version_requirements: *id002
-- !ruby/object:Gem::Dependency
- name: hoe
prerelease: false
- requirement: &id003 !ruby/object:Gem::Requirement
- none: false
- requirements:
- - - ~>
- - !ruby/object:Gem::Version
- version: "2.12"
+ version_requirements: !ruby/object:Gem::Requirement
+ requirements:
+ - - "~>"
+ - !ruby/object:Gem::Version
+ version: '10.4'
+- !ruby/object:Gem::Dependency
+ name: rspec
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
+ - - "~>"
+ - !ruby/object:Gem::Version
+ version: '3.2'
type: :development
- version_requirements: *id003
-description: Numerical integration for Ruby, with a simple interface
-email:
-- NO_EMAIL
-- clbustos_at_gmail.com
+ prerelease: false
+ version_requirements: !ruby/object:Gem::Requirement
+ requirements:
+ - - "~>"
+ - !ruby/object:Gem::Version
+ version: '3.2'
+description: Numerical integration for Ruby with a simple interface.
+email:
+- clbustos at gmail.com
executables: []
-
extensions: []
-
-extra_rdoc_files:
-- History.txt
-- Manifest.txt
-- README.txt
-files:
-- .autotest
+extra_rdoc_files: []
+files:
+- ".gitignore"
+- ".travis.yml"
+- ".yardopts"
+- CONTRIBUTING.md
+- Gemfile
- History.txt
-- Manifest.txt
-- README.txt
+- README.md
- Rakefile
+- benchmark/accuracy.rb
+- benchmark/speed.rb
+- integration.gemspec
- lib/integration.rb
+- lib/integration/methods.rb
+- lib/integration/version.rb
+- lib/opencl/Makefile
+- lib/opencl/integration_host.c
+- lib/opencl/opencl_minimization.rb
+- lib/opencl/unidimensional_kernel.cl
- spec/integration_spec.rb
-- spec/spec.opts
- spec/spec_helper.rb
-- .gemtest
-has_rdoc: true
-homepage: http://github.com/clbustos/integration
-licenses: []
-
+homepage: http://sciruby.com
+licenses:
+- See README.md.
+metadata: {}
post_install_message:
-rdoc_options:
-- --main
-- README.txt
-require_paths:
+rdoc_options: []
+require_paths:
- lib
-required_ruby_version: !ruby/object:Gem::Requirement
- none: false
- requirements:
+required_ruby_version: !ruby/object:Gem::Requirement
+ requirements:
- - ">="
- - !ruby/object:Gem::Version
- version: "0"
-required_rubygems_version: !ruby/object:Gem::Requirement
- none: false
- requirements:
+ - !ruby/object:Gem::Version
+ version: 1.9.3
+required_rubygems_version: !ruby/object:Gem::Requirement
+ requirements:
- - ">="
- - !ruby/object:Gem::Version
- version: "0"
+ - !ruby/object:Gem::Version
+ version: '0'
requirements: []
-
-rubyforge_project: integration
-rubygems_version: 1.6.0
+rubyforge_project:
+rubygems_version: 2.4.5
signing_key:
-specification_version: 3
-summary: Numerical integration for Ruby, with a simple interface
-test_files: []
-
+specification_version: 4
+summary: Numerical integration for Ruby with a simple interface.
+test_files:
+- benchmark/accuracy.rb
+- benchmark/speed.rb
+- spec/integration_spec.rb
+- spec/spec_helper.rb
diff --git a/spec/integration_spec.rb b/spec/integration_spec.rb
index 90383e5..67e6667 100644
--- a/spec/integration_spec.rb
+++ b/spec/integration_spec.rb
@@ -1,60 +1,66 @@
-require File.expand_path(File.dirname(__FILE__)+"/spec_helper.rb")
+$LOAD_PATH.unshift File.expand_path('../spec', __FILE__)
+
+require 'spec_helper'
+
describe Integration do
- it "should respond integration based on ruby methods" do
- a=lambda {|x| x**2}
- # Integration over [1,2]=x^3/3=7/3
-
- methods=[:rectangle,:trapezoid, :simpson, :adaptive_quadrature, :romberg]
- methods.each do |m|
- Integration.integrate(1,2,{:method=>m,:tolerance=>1e-7},&a).should be_within(1e-6).of(7/3.0)
+ a = lambda { |x| x**2 }
+ b = lambda { |x| Math.log(x) / x**2 }
+ b2 = lambda { |x| -(Math.log(x) + 1) / x }
+
+ # Integration over [1,2]=x^3/3=7/3
+ methods = [:rectangle, :trapezoid, :simpson, :adaptive_quadrature, :romberg,
+ :gauss, :gauss_kronrod, :simpson3by8, :boole, :open_trapezoid,
+ :milne]
+
+ methods.each do |m|
+ it "should integrate int_{1}^2{2} x^2 correctly with ruby method #{m}" do
+ Integration.integrate(1, 2, { method: m, tolerance: 1e-8 }, &a).should be_within(1e-6).of(7.0 / 3)
end
+ it "should integrate int_{1}^2{2} log(x)/x^2 correctly with ruby method #{m}" do
+ Integration.integrate(1, 2, { method: m, tolerance: 1e-8 }, &b).should be_within(1e-6).of(
+ b2[2] - b2[1]
+ )
+ end
end
-
- it "should return a correct value for a complex integration with ruby methods" do
- normal_pdf=lambda {|x| (1/Math.sqrt(2*Math::PI))*Math.exp(-(x**2/2))}
- Integration.integrate(0,1,{:tolerance=>1e-12,:method=>:simpson},&normal_pdf).should be_within(1e-11).of(0.341344746068)
- Integration.integrate(0,1,{:tolerance=>1e-12,:method=>:adaptive_quadrature},&normal_pdf).should be_within(1e-11).of(0.341344746068)
- end
- it "should return a correct value for a complex integration with gsl methods" do
- normal_pdf=lambda {|x| (1/Math.sqrt(2*Math::PI))*Math.exp(-(x**2/2))}
- Integration.integrate(0,1,{:tolerance=>1e-12,:method=>:qng},&normal_pdf).should be_within(1e-11).of(0.341344746068)
- Integration.integrate(0,1,{:tolerance=>1e-12,:method=>:qag},&normal_pdf).should be_within(1e-11).of(0.341344746068)
+
+ it 'should return correct for trapezoid' do
+ a = rand
+ b = rand * 10
+ f = lambda { |x| x * a }
+ Integration.trapezoid(0, b, 2, &f).should be_within(1e-14).of((a * b**2) / 2.0)
end
-
- it "should return correct integration for infinity bounds" do
- if Integration.has_gsl?
- normal_pdf=lambda {|x| (1/Math.sqrt(2*Math::PI))*Math.exp(-(x**2/2))}
+ it 'should return a correct value for a complex integration with ruby methods' do
+ normal_pdf = lambda { |x| (1 / Math.sqrt(2 * Math::PI)) * Math.exp(-(x**2 / 2)) }
+ Integration.integrate(0, 1, { tolerance: 1e-12, method: :simpson }, &normal_pdf).should be_within(1e-11).of(0.341344746068)
+ Integration.integrate(0, 1, { tolerance: 1e-12, method: :adaptive_quadrature }, &normal_pdf).should be_within(1e-11).of(0.341344746068)
+ end
- Integration.integrate(Integration::MInfinity, Integration::Infinity,{:tolerance=>1e-10}, &normal_pdf).should be_within(1e-09).of(1)
- else
- pending("GSL not available")
- end
+ it 'should return a correct value for a complex integration with gsl methods' do
+ normal_pdf = lambda { |x| (1 / Math.sqrt(2 * Math::PI)) * Math.exp(-(x**2 / 2)) }
+ Integration.integrate(0, 1, { tolerance: 1e-12, method: :qng }, &normal_pdf).should be_within(1e-11).of(0.341344746068)
+ Integration.integrate(0, 1, { tolerance: 1e-12, method: :qag }, &normal_pdf).should be_within(1e-11).of(0.341344746068)
end
- it "should return correct integration for infinity lower bound" do
- if Integration.has_gsl?
- normal_pdf=lambda {|x| (1/Math.sqrt(2*Math::PI))*Math.exp(-(x**2/2))}
- Integration.integrate(Integration::MInfinity, 0 , {:tolerance=>1e-10}, &normal_pdf).should be_within(1e-09).of(0.5)
+ it 'should return correct integration for infinity bounds' do
+ normal_pdf = lambda { |x| (1 / Math.sqrt(2 * Math::PI)) * Math.exp(-(x**2 / 2)) }
- else
- pending("GSL not available")
- end
+ Integration.integrate(Integration::MInfinity, Integration::Infinity, { tolerance: 1e-10 }, &normal_pdf).should be_within(1e-09).of(1)
end
- it "should return correct integration for infinity upper bound" do
- if Integration.has_gsl?
- normal_pdf=lambda {|x| (1/Math.sqrt(2*Math::PI))*Math.exp(-(x**2/2))}
- Integration.integrate(0,Integration::Infinity,{:tolerance=>1e-10}, &normal_pdf).should be_within(1e-09).of(0.5)
+ it 'should return correct integration for infinity lower bound' do
+ normal_pdf = lambda { |x| (1 / Math.sqrt(2 * Math::PI)) * Math.exp(-(x**2 / 2)) }
+ Integration.integrate(Integration::MInfinity, 0, { tolerance: 1e-10 }, &normal_pdf).should be_within(1e-09).of(0.5)
+ end
- else
- pending("GSL not available")
- end
+ it 'should return correct integration for infinity upper bound' do
+ normal_pdf = lambda { |x| (1 / Math.sqrt(2 * Math::PI)) * Math.exp(-(x**2 / 2)) }
+ Integration.integrate(0, Integration::Infinity, { tolerance: 1e-10 }, &normal_pdf).should be_within(1e-09).of(0.5)
end
- it "should raise an error if a ruby methods is called with infinite bounds" do
- normal_pdf=lambda {|x| (1/Math.sqrt(2*Math::PI))*Math.exp(-(x**2/2))}
- lambda {Integration.integrate(0,Integration::Infinity,{:method=>:simpson}, &normal_pdf).should be_within(1e-09).of(0.5)}.should raise_exception()
+
+ it 'should raise an error if a ruby methods is called with infinite bounds' do
+ normal_pdf = lambda { |x| (1 / Math.sqrt(2 * Math::PI)) * Math.exp(-(x**2 / 2)) }
+ lambda { Integration.integrate(0, Integration::Infinity, { method: :simpson }, &normal_pdf).should be_within(1e-09).of(0.5) }.should raise_exception
end
end
-
diff --git a/spec/spec.opts b/spec/spec.opts
deleted file mode 100644
index d8ed776..0000000
--- a/spec/spec.opts
+++ /dev/null
@@ -1,3 +0,0 @@
---color
--f s
--b
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index ce9081d..9c62ae4 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,11 +1,28 @@
-$:.unshift(File.dirname(__FILE__)+"/../lib")
+$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
+
+require 'integration'
+require 'rspec'
+
begin
require 'simplecov'
SimpleCov.start do
- add_filter "/spec/"
- add_group "Libraries", "lib"
+ add_filter '/spec/'
+ add_group 'Libraries', 'lib'
end
rescue LoadError
end
-require 'rspec'
-require 'integration'
+
+RSpec.configure do |config|
+ config.expect_with :rspec do |c|
+ c.syntax = [:should, :expect]
+ end
+
+ # Use color in STDOUT
+ config.color = true
+
+ # Use color not only in STDOUT but also in pagers and files
+ config.tty = true
+
+ # Use the specified formatter
+ config.formatter = :documentation # :progress, :html, :textmate
+end
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/ruby-integration.git
More information about the Pkg-ruby-extras-commits
mailing list