[DRE-commits] [ruby-numo-narray] 01/05: Import Upstream version 0.9.0.7
Youhei SASAKI
uwabami-guest at moszumanska.debian.org
Wed Jun 21 08:37:32 UTC 2017
This is an automated email from the git hooks/post-receive script.
uwabami-guest pushed a commit to branch master
in repository ruby-numo-narray.
commit b89f92d486d3439f732a5c6d325669d63a439c2e
Author: Youhei SASAKI <uwabami at gfd-dennou.org>
Date: Wed Jun 21 16:57:22 2017 +0900
Import Upstream version 0.9.0.7
---
Gemfile | 4 +
README.md | 60 +
Rakefile | 66 +
ext/numo/narray/SFMT-params.h | 97 ++
ext/numo/narray/SFMT-params19937.h | 46 +
ext/numo/narray/SFMT.c | 620 ++++++++
ext/numo/narray/SFMT.h | 157 ++
ext/numo/narray/array.c | 642 ++++++++
ext/numo/narray/data.c | 966 ++++++++++++
ext/numo/narray/depend.erb | 34 +
ext/numo/narray/extconf.rb | 97 ++
ext/numo/narray/gen/cogen.rb | 56 +
ext/numo/narray/gen/def/bit.rb | 36 +
ext/numo/narray/gen/def/dcomplex.rb | 38 +
ext/numo/narray/gen/def/dfloat.rb | 36 +
ext/numo/narray/gen/def/int16.rb | 35 +
ext/numo/narray/gen/def/int32.rb | 35 +
ext/numo/narray/gen/def/int64.rb | 35 +
ext/numo/narray/gen/def/int8.rb | 35 +
ext/numo/narray/gen/def/robject.rb | 36 +
ext/numo/narray/gen/def/scomplex.rb | 38 +
ext/numo/narray/gen/def/sfloat.rb | 36 +
ext/numo/narray/gen/def/uint16.rb | 35 +
ext/numo/narray/gen/def/uint32.rb | 35 +
ext/numo/narray/gen/def/uint64.rb | 35 +
ext/numo/narray/gen/def/uint8.rb | 35 +
ext/numo/narray/gen/erbpp2.rb | 325 ++++
ext/numo/narray/gen/narray_def.rb | 252 +++
ext/numo/narray/gen/spec.rb | 396 +++++
ext/numo/narray/gen/tmpl/accum.c | 48 +
ext/numo/narray/gen/tmpl/accum_binary.c | 96 ++
ext/numo/narray/gen/tmpl/accum_index.c | 71 +
ext/numo/narray/gen/tmpl/alloc_func.c | 107 ++
ext/numo/narray/gen/tmpl/allocate.c | 35 +
ext/numo/narray/gen/tmpl/aref.c | 53 +
ext/numo/narray/gen/tmpl/aset.c | 65 +
ext/numo/narray/gen/tmpl/binary.c | 57 +
ext/numo/narray/gen/tmpl/binary2.c | 59 +
ext/numo/narray/gen/tmpl/binary_s.c | 34 +
ext/numo/narray/gen/tmpl/bincount.c | 180 +++
ext/numo/narray/gen/tmpl/cast.c | 44 +
ext/numo/narray/gen/tmpl/cast_array.c | 13 +
ext/numo/narray/gen/tmpl/class.c | 9 +
ext/numo/narray/gen/tmpl/clip.c | 118 ++
ext/numo/narray/gen/tmpl/coerce_cast.c | 10 +
ext/numo/narray/gen/tmpl/cond_binary.c | 55 +
ext/numo/narray/gen/tmpl/cond_unary.c | 45 +
ext/numo/narray/gen/tmpl/cum.c | 49 +
ext/numo/narray/gen/tmpl/each.c | 43 +
ext/numo/narray/gen/tmpl/each_with_index.c | 64 +
ext/numo/narray/gen/tmpl/extract.c | 23 +
ext/numo/narray/gen/tmpl/extract_data.c | 48 +
ext/numo/narray/gen/tmpl/eye.c | 91 ++
ext/numo/narray/gen/tmpl/fill.c | 38 +
ext/numo/narray/gen/tmpl/format.c | 60 +
ext/numo/narray/gen/tmpl/format_to_a.c | 47 +
ext/numo/narray/gen/tmpl/frexp.c | 37 +
ext/numo/narray/gen/tmpl/init_class.c | 20 +
ext/numo/narray/gen/tmpl/init_module.c | 12 +
ext/numo/narray/gen/tmpl/inspect.c | 20 +
ext/numo/narray/gen/tmpl/lib.c | 45 +
ext/numo/narray/gen/tmpl/logseq.c | 82 +
ext/numo/narray/gen/tmpl/map_with_index.c | 94 ++
ext/numo/narray/gen/tmpl/median.c | 64 +
ext/numo/narray/gen/tmpl/minmax.c | 46 +
ext/numo/narray/gen/tmpl/module.c | 9 +
ext/numo/narray/gen/tmpl/new_dim0.c | 12 +
ext/numo/narray/gen/tmpl/poly.c | 49 +
ext/numo/narray/gen/tmpl/pow.c | 78 +
ext/numo/narray/gen/tmpl/powint.c | 17 +
ext/numo/narray/gen/tmpl/qsort.c | 150 ++
ext/numo/narray/gen/tmpl/rand.c | 165 ++
ext/numo/narray/gen/tmpl/rand_norm.c | 119 ++
ext/numo/narray/gen/tmpl/seq.c | 92 ++
ext/numo/narray/gen/tmpl/set2.c | 56 +
ext/numo/narray/gen/tmpl/sort.c | 47 +
ext/numo/narray/gen/tmpl/sort_index.c | 102 ++
ext/numo/narray/gen/tmpl/store.c | 41 +
ext/numo/narray/gen/tmpl/store_array.c | 102 ++
ext/numo/narray/gen/tmpl/store_bit.c | 55 +
ext/numo/narray/gen/tmpl/store_from.c | 53 +
ext/numo/narray/gen/tmpl/store_numeric.c | 9 +
ext/numo/narray/gen/tmpl/to_a.c | 41 +
ext/numo/narray/gen/tmpl/unary.c | 58 +
ext/numo/narray/gen/tmpl/unary2.c | 58 +
ext/numo/narray/gen/tmpl/unary_ret2.c | 33 +
ext/numo/narray/gen/tmpl/unary_s.c | 57 +
ext/numo/narray/gen/tmpl_bit/allocate.c | 24 +
ext/numo/narray/gen/tmpl_bit/aref.c | 55 +
ext/numo/narray/gen/tmpl_bit/aset.c | 65 +
ext/numo/narray/gen/tmpl_bit/binary.c | 94 ++
ext/numo/narray/gen/tmpl_bit/bit_count.c | 85 +
ext/numo/narray/gen/tmpl_bit/bit_reduce.c | 129 ++
ext/numo/narray/gen/tmpl_bit/each.c | 44 +
ext/numo/narray/gen/tmpl_bit/each_with_index.c | 66 +
ext/numo/narray/gen/tmpl_bit/extract.c | 25 +
ext/numo/narray/gen/tmpl_bit/fill.c | 65 +
ext/numo/narray/gen/tmpl_bit/format.c | 61 +
ext/numo/narray/gen/tmpl_bit/format_to_a.c | 48 +
ext/numo/narray/gen/tmpl_bit/inspect.c | 18 +
ext/numo/narray/gen/tmpl_bit/mask.c | 132 ++
ext/numo/narray/gen/tmpl_bit/none_p.c | 14 +
ext/numo/narray/gen/tmpl_bit/store_array.c | 104 ++
ext/numo/narray/gen/tmpl_bit/store_bit.c | 66 +
ext/numo/narray/gen/tmpl_bit/store_from.c | 56 +
ext/numo/narray/gen/tmpl_bit/to_a.c | 43 +
ext/numo/narray/gen/tmpl_bit/unary.c | 77 +
ext/numo/narray/gen/tmpl_bit/where.c | 86 ++
ext/numo/narray/gen/tmpl_bit/where2.c | 91 ++
ext/numo/narray/index.c | 842 ++++++++++
ext/numo/narray/math.c | 147 ++
ext/numo/narray/narray.c | 1975 ++++++++++++++++++++++++
ext/numo/narray/ndloop.c | 1961 +++++++++++++++++++++++
ext/numo/narray/numo/compat.h | 23 +
ext/numo/narray/numo/intern.h | 109 ++
ext/numo/narray/numo/narray.h | 429 +++++
ext/numo/narray/numo/ndloop.h | 94 ++
ext/numo/narray/numo/template.h | 136 ++
ext/numo/narray/numo/types/bit.h | 33 +
ext/numo/narray/numo/types/complex.h | 409 +++++
ext/numo/narray/numo/types/complex_macro.h | 375 +++++
ext/numo/narray/numo/types/dcomplex.h | 44 +
ext/numo/narray/numo/types/dfloat.h | 42 +
ext/numo/narray/numo/types/float_def.h | 34 +
ext/numo/narray/numo/types/float_macro.h | 186 +++
ext/numo/narray/numo/types/int16.h | 21 +
ext/numo/narray/numo/types/int32.h | 21 +
ext/numo/narray/numo/types/int64.h | 21 +
ext/numo/narray/numo/types/int8.h | 21 +
ext/numo/narray/numo/types/int_macro.h | 35 +
ext/numo/narray/numo/types/real_accum.h | 440 ++++++
ext/numo/narray/numo/types/robj_macro.h | 75 +
ext/numo/narray/numo/types/robject.h | 27 +
ext/numo/narray/numo/types/scomplex.h | 44 +
ext/numo/narray/numo/types/sfloat.h | 43 +
ext/numo/narray/numo/types/uint16.h | 18 +
ext/numo/narray/numo/types/uint32.h | 18 +
ext/numo/narray/numo/types/uint64.h | 18 +
ext/numo/narray/numo/types/uint8.h | 18 +
ext/numo/narray/numo/types/uint_macro.h | 32 +
ext/numo/narray/numo/types/xint_macro.h | 173 +++
ext/numo/narray/rand.c | 72 +
ext/numo/narray/step.c | 501 ++++++
ext/numo/narray/struct.c | 885 +++++++++++
lib/erbpp.rb | 294 ++++
lib/erbpp/line_number.rb | 133 ++
lib/erbpp/narray_def.rb | 381 +++++
lib/numo/narray.rb | 8 +
lib/numo/narray/extra.rb | 1262 +++++++++++++++
numo-narray.gemspec | 36 +
spec/bit_spec.rb | 93 ++
spec/narray_spec.rb | 250 +++
152 files changed, 20930 insertions(+)
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..033d820
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,4 @@
+source 'https://rubygems.org'
+
+# Specify your gem's dependencies in narray-devel.gemspec
+gemspec
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..9f2004d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,60 @@
+# Numo::NArray - New NArray class library for Ruby/Numo (NUmerical MOdule)
+
+[![Binder](http://mybinder.org/badge.svg)](http://mybinder.org/repo/ruby-numo/narray)
+[![Build Status](https://travis-ci.org/ruby-numo/narray.svg?branch=master)](https://travis-ci.org/ruby-numo/narray)
+
+[GitHub](https://github.com/ruby-numo/narray)
+ | [RubyGems](https://rubygems.org/gems/numo-narray)
+
+Numo::NArray is an Numerical N-dimensional Array class
+for fast processing and easy manipulation of multi-dimensional numerical data,
+similar to numpy.ndaray.
+This project is the successor to [Ruby/NArray](http://masa16.github.io/narray/).
+
+under development
+
+## Documentation
+All documents are primitive.
+
+* [Numo::NArray API Doc](http://ruby-numo.github.io/narray/narray/frames.html)
+* [Numo::NArray vs numpy](https://github.com/ruby-numo/narray/wiki/Numo-vs-numpy)
+* [Numo::NArray vs ndarray](https://github.com/ruby-numo/narray/wiki/Numo-vs-ndarray)
+* [Numo::NArray Overview](https://github.com/ruby-numo/narray/wiki/Numo::NArray%E6%A6%82%E8%A6%81) (in Japanese)
+
+## Related Projects
+* [Numo::Linalg](https://github.com/ruby-numo/linalg) - Linear Algebra library with [LAPACK](http://www.netlib.org/lapack/).
+* [Numo::GSL](https://github.com/ruby-numo/gsl) - Ruby interface for [GSL (GNU Scientific Library)](http://www.gnu.org/software/gsl/).
+* [Numo::FFTE](https://github.com/ruby-numo/ffte) - Ruby interface for [FFTE (A Fast Fourier Transform library with radix-2,3,5)](http://www.ffte.jp/).
+* [Numo::Gnuplot](https://github.com/ruby-numo/gnuplot) - Simple and easy-to-use Gnuplot interface.
+
+## Installation
+### Requirement
+Ruby ver 2.1 and later.
+
+### Ubuntu, Debian, Bash on Windows
+```shell
+apt install -y git ruby gcc ruby-dev rake make
+gem install specific_install
+gem specific_install https://github.com/ruby-numo/narray.git
+```
+
+## Quick start
+An example
+```ruby
+[1] pry(main)> require "numo/narray"
+=> true
+[2] pry(main)> a = Numo::DFloat.new(3,5).seq
+=> Numo::DFloat#shape=[3,5]
+[[0, 1, 2, 3, 4],
+ [5, 6, 7, 8, 9],
+ [10, 11, 12, 13, 14]]
+[3] pry(main)> a.shape
+=> [3, 5]
+[4] pry(main)> a.ndim
+=> 2
+[5] pry(main)> a.class
+=> Numo::DFloat
+[6] pry(main)> a.size
+=> 15
+```
+For more examples, check out this [narray version of 100 numpy exercises](https://github.com/ruby-numo/narray/wiki/100-narray-exercises) (and the [IRuby Notebook](https://github.com/ruby-numo/narray/blob/master/100-narray-exercises.ipynb)).
diff --git a/Rakefile b/Rakefile
new file mode 100644
index 0000000..004e2e9
--- /dev/null
+++ b/Rakefile
@@ -0,0 +1,66 @@
+require "bundler/gem_tasks"
+begin
+
+task :doc do
+ dir = "ext/numo/narray"
+ src = %w[array.c data.c index.c math.c narray.c rand.c struct.c].
+ map{|s| File.join(dir,s)} +
+ [File.join(dir,"types/*.c"), "lib/numo/narray/extra.rb"]
+ sh "cd ext/numo/narray; ruby extconf.rb; make src"
+ sh "rm -rf yard .yardoc; yard doc -o yard -m markdown -r README.md #{src.join(' ')}"
+end
+
+require "rake/extensiontask"
+require "rake_compiler_dock"
+require "shellwords"
+
+spec = Bundler::GemHelper.gemspec
+
+cross_platforms = ["x86-mingw32", "x64-mingw32"]
+Rake::ExtensionTask.new("numo/narray", spec) do |ext|
+ ext.cross_compile = true
+ ext.cross_platform = cross_platforms
+end
+
+pkg_dir = "pkg"
+windows_gem_paths = cross_platforms.collect do |platform|
+ File.join(pkg_dir, "#{spec.full_name}-#{platform}.gem")
+end
+
+namespace :build do
+ directory pkg_dir
+
+ desc "Build gems for Windows into the pkg directory"
+ task :windows => pkg_dir do
+ build_dir = "tmp/windows"
+ rm_rf build_dir
+ mkdir_p build_dir
+
+ commands = [
+ ["git", "clone", "file://#{Dir.pwd}/.git", build_dir],
+ ["cd", build_dir],
+ ["bundle"],
+ ["rake", "cross", "native", "gem"],
+ ]
+ raw_commands = commands.collect do |command|
+ Shellwords.join(command)
+ end
+ raw_command_line = raw_commands.join(" && ")
+
+ RakeCompilerDock.sh(raw_command_line)
+
+ cp(Dir.glob("#{build_dir}/#{pkg_dir}/*.gem"),
+ "#{pkg_dir}/")
+ end
+end
+
+namespace :release do
+ task :windows => "build:windows" do
+ windows_gem_paths.each do |path|
+ ruby("-S", "gem", "push", path)
+ end
+ end
+end
+
+rescue LoadError
+end
diff --git a/ext/numo/narray/SFMT-params.h b/ext/numo/narray/SFMT-params.h
new file mode 100644
index 0000000..cda2ccc
--- /dev/null
+++ b/ext/numo/narray/SFMT-params.h
@@ -0,0 +1,97 @@
+#ifndef SFMT_PARAMS_H
+#define SFMT_PARAMS_H
+
+#if !defined(MEXP)
+//#ifdef __GNUC__
+// #warning "MEXP is not defined. I assume MEXP is 19937."
+//#endif
+ #define MEXP 19937
+#endif
+/*-----------------
+ BASIC DEFINITIONS
+ -----------------*/
+/** Mersenne Exponent. The period of the sequence
+ * is a multiple of 2^MEXP-1.
+ * #define MEXP 19937 */
+/** SFMT generator has an internal state array of 128-bit integers,
+ * and N is its size. */
+#define N (MEXP / 128 + 1)
+/** N32 is the size of internal state array when regarded as an array
+ * of 32-bit integers.*/
+#define N32 (N * 4)
+/** N64 is the size of internal state array when regarded as an array
+ * of 64-bit integers.*/
+#define N64 (N * 2)
+
+/*----------------------
+ the parameters of SFMT
+ following definitions are in paramsXXXX.h file.
+ ----------------------*/
+/** the pick up position of the array.
+#define POS1 122
+*/
+
+/** the parameter of shift left as four 32-bit registers.
+#define SL1 18
+ */
+
+/** the parameter of shift left as one 128-bit register.
+ * The 128-bit integer is shifted by (SL2 * 8) bits.
+#define SL2 1
+*/
+
+/** the parameter of shift right as four 32-bit registers.
+#define SR1 11
+*/
+
+/** the parameter of shift right as one 128-bit register.
+ * The 128-bit integer is shifted by (SL2 * 8) bits.
+#define SR2 1
+*/
+
+/** A bitmask, used in the recursion. These parameters are introduced
+ * to break symmetry of SIMD.
+#define MSK1 0xdfffffefU
+#define MSK2 0xddfecb7fU
+#define MSK3 0xbffaffffU
+#define MSK4 0xbffffff6U
+*/
+
+/** These definitions are part of a 128-bit period certification vector.
+#define PARITY1 0x00000001U
+#define PARITY2 0x00000000U
+#define PARITY3 0x00000000U
+#define PARITY4 0xc98e126aU
+*/
+
+#if MEXP == 607
+ #include "SFMT-params607.h"
+#elif MEXP == 1279
+ #include "SFMT-params1279.h"
+#elif MEXP == 2281
+ #include "SFMT-params2281.h"
+#elif MEXP == 4253
+ #include "SFMT-params4253.h"
+#elif MEXP == 11213
+ #include "SFMT-params11213.h"
+#elif MEXP == 19937
+ #include "SFMT-params19937.h"
+#elif MEXP == 44497
+ #include "SFMT-params44497.h"
+#elif MEXP == 86243
+ #include "SFMT-params86243.h"
+#elif MEXP == 132049
+ #include "SFMT-params132049.h"
+#elif MEXP == 216091
+ #include "SFMT-params216091.h"
+#else
+#ifdef __GNUC__
+ #error "MEXP is not valid."
+ #undef MEXP
+#else
+ #undef MEXP
+#endif
+
+#endif
+
+#endif /* SFMT_PARAMS_H */
diff --git a/ext/numo/narray/SFMT-params19937.h b/ext/numo/narray/SFMT-params19937.h
new file mode 100644
index 0000000..04708cd
--- /dev/null
+++ b/ext/numo/narray/SFMT-params19937.h
@@ -0,0 +1,46 @@
+#ifndef SFMT_PARAMS19937_H
+#define SFMT_PARAMS19937_H
+
+#define POS1 122
+#define SL1 18
+#define SL2 1
+#define SR1 11
+#define SR2 1
+#define MSK1 0xdfffffefU
+#define MSK2 0xddfecb7fU
+#define MSK3 0xbffaffffU
+#define MSK4 0xbffffff6U
+#define PARITY1 0x00000001U
+#define PARITY2 0x00000000U
+#define PARITY3 0x00000000U
+#define PARITY4 0x13c9e684U
+
+
+/* PARAMETERS FOR ALTIVEC */
+#if defined(__APPLE__) /* For OSX */
+ #define ALTI_SL1 (vector unsigned int)(SL1, SL1, SL1, SL1)
+ #define ALTI_SR1 (vector unsigned int)(SR1, SR1, SR1, SR1)
+ #define ALTI_MSK (vector unsigned int)(MSK1, MSK2, MSK3, MSK4)
+ #define ALTI_MSK64 \
+ (vector unsigned int)(MSK2, MSK1, MSK4, MSK3)
+ #define ALTI_SL2_PERM \
+ (vector unsigned char)(1,2,3,23,5,6,7,0,9,10,11,4,13,14,15,8)
+ #define ALTI_SL2_PERM64 \
+ (vector unsigned char)(1,2,3,4,5,6,7,31,9,10,11,12,13,14,15,0)
+ #define ALTI_SR2_PERM \
+ (vector unsigned char)(7,0,1,2,11,4,5,6,15,8,9,10,17,12,13,14)
+ #define ALTI_SR2_PERM64 \
+ (vector unsigned char)(15,0,1,2,3,4,5,6,17,8,9,10,11,12,13,14)
+#else /* For OTHER OSs(Linux?) */
+ #define ALTI_SL1 {SL1, SL1, SL1, SL1}
+ #define ALTI_SR1 {SR1, SR1, SR1, SR1}
+ #define ALTI_MSK {MSK1, MSK2, MSK3, MSK4}
+ #define ALTI_MSK64 {MSK2, MSK1, MSK4, MSK3}
+ #define ALTI_SL2_PERM {1,2,3,23,5,6,7,0,9,10,11,4,13,14,15,8}
+ #define ALTI_SL2_PERM64 {1,2,3,4,5,6,7,31,9,10,11,12,13,14,15,0}
+ #define ALTI_SR2_PERM {7,0,1,2,11,4,5,6,15,8,9,10,17,12,13,14}
+ #define ALTI_SR2_PERM64 {15,0,1,2,3,4,5,6,17,8,9,10,11,12,13,14}
+#endif /* For OSX */
+#define IDSTR "SFMT-19937:122-18-1-11-1:dfffffef-ddfecb7f-bffaffff-bffffff6"
+
+#endif /* SFMT_PARAMS19937_H */
diff --git a/ext/numo/narray/SFMT.c b/ext/numo/narray/SFMT.c
new file mode 100644
index 0000000..d36465d
--- /dev/null
+++ b/ext/numo/narray/SFMT.c
@@ -0,0 +1,620 @@
+/**
+ * @file SFMT.c
+ * @brief SIMD oriented Fast Mersenne Twister(SFMT)
+ *
+ * @author Mutsuo Saito (Hiroshima University)
+ * @author Makoto Matsumoto (Hiroshima University)
+ *
+ * Copyright (C) 2006,2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima
+ * University. All rights reserved.
+ *
+ * The new BSD License is applied to this software, see LICENSE.txt
+ */
+#include <string.h>
+#include <assert.h>
+#include "SFMT.h"
+#include "SFMT-params.h"
+
+#if defined(__BIG_ENDIAN__) && !defined(__amd64) && !defined(BIG_ENDIAN64)
+#define BIG_ENDIAN64 1
+#endif
+#if defined(HAVE_ALTIVEC) && !defined(BIG_ENDIAN64)
+#define BIG_ENDIAN64 1
+#endif
+#if defined(ONLY64) && !defined(BIG_ENDIAN64)
+ #if defined(__GNUC__)
+ #error "-DONLY64 must be specified with -DBIG_ENDIAN64"
+ #endif
+#undef ONLY64
+#endif
+/*------------------------------------------------------
+ 128-bit SIMD data type for Altivec, SSE2 or standard C
+ ------------------------------------------------------*/
+#if defined(HAVE_ALTIVEC)
+ #if !defined(__APPLE__)
+ #include <altivec.h>
+ #endif
+/** 128-bit data structure */
+union W128_T {
+ vector unsigned int s;
+ uint32_t u[4];
+};
+/** 128-bit data type */
+typedef union W128_T w128_t;
+
+#elif defined(HAVE_SSE2)
+ #include <emmintrin.h>
+
+/** 128-bit data structure */
+union W128_T {
+ __m128i si;
+ uint32_t u[4];
+};
+/** 128-bit data type */
+typedef union W128_T w128_t;
+
+#else
+
+/** 128-bit data structure */
+struct W128_T {
+ uint32_t u[4];
+};
+/** 128-bit data type */
+typedef struct W128_T w128_t;
+
+#endif
+
+/*--------------------------------------
+ FILE GLOBAL VARIABLES
+ internal state, index counter and flag
+ --------------------------------------*/
+/** the 128-bit internal state array */
+static w128_t sfmt[N];
+/** the 32bit integer pointer to the 128-bit internal state array */
+static uint32_t *psfmt32 = &sfmt[0].u[0];
+#if !defined(BIG_ENDIAN64) || defined(ONLY64)
+/** the 64bit integer pointer to the 128-bit internal state array */
+static uint64_t *psfmt64 = (uint64_t *)&sfmt[0].u[0];
+#endif
+/** index counter to the 32-bit internal state array */
+static int idx;
+/** a flag: it is 0 if and only if the internal state is not yet
+ * initialized. */
+static int initialized = 0;
+/** a parity check vector which certificate the period of 2^{MEXP} */
+static uint32_t parity[4] = {PARITY1, PARITY2, PARITY3, PARITY4};
+
+/*----------------
+ STATIC FUNCTIONS
+ ----------------*/
+inline static int idxof(int i);
+inline static void rshift128(w128_t *out, w128_t const *in, int shift);
+inline static void lshift128(w128_t *out, w128_t const *in, int shift);
+inline static void gen_rand_all(void);
+inline static void gen_rand_array(w128_t *array, int size);
+inline static uint32_t func1(uint32_t x);
+inline static uint32_t func2(uint32_t x);
+static void period_certification(void);
+#if defined(BIG_ENDIAN64) && !defined(ONLY64)
+inline static void swap(w128_t *array, int size);
+#endif
+
+#if defined(HAVE_ALTIVEC)
+ #include "SFMT-alti.h"
+#elif defined(HAVE_SSE2)
+ #include "SFMT-sse2.h"
+#endif
+
+/**
+ * This function simulate a 64-bit index of LITTLE ENDIAN
+ * in BIG ENDIAN machine.
+ */
+#ifdef ONLY64
+inline static int idxof(int i) {
+ return i ^ 1;
+}
+#else
+inline static int idxof(int i) {
+ return i;
+}
+#endif
+/**
+ * This function simulates SIMD 128-bit right shift by the standard C.
+ * The 128-bit integer given in in is shifted by (shift * 8) bits.
+ * This function simulates the LITTLE ENDIAN SIMD.
+ * @param out the output of this function
+ * @param in the 128-bit data to be shifted
+ * @param shift the shift value
+ */
+#ifdef ONLY64
+inline static void rshift128(w128_t *out, w128_t const *in, int shift) {
+ uint64_t th, tl, oh, ol;
+
+ th = ((uint64_t)in->u[2] << 32) | ((uint64_t)in->u[3]);
+ tl = ((uint64_t)in->u[0] << 32) | ((uint64_t)in->u[1]);
+
+ oh = th >> (shift * 8);
+ ol = tl >> (shift * 8);
+ ol |= th << (64 - shift * 8);
+ out->u[0] = (uint32_t)(ol >> 32);
+ out->u[1] = (uint32_t)ol;
+ out->u[2] = (uint32_t)(oh >> 32);
+ out->u[3] = (uint32_t)oh;
+}
+#else
+inline static void rshift128(w128_t *out, w128_t const *in, int shift) {
+ uint64_t th, tl, oh, ol;
+
+ th = ((uint64_t)in->u[3] << 32) | ((uint64_t)in->u[2]);
+ tl = ((uint64_t)in->u[1] << 32) | ((uint64_t)in->u[0]);
+
+ oh = th >> (shift * 8);
+ ol = tl >> (shift * 8);
+ ol |= th << (64 - shift * 8);
+ out->u[1] = (uint32_t)(ol >> 32);
+ out->u[0] = (uint32_t)ol;
+ out->u[3] = (uint32_t)(oh >> 32);
+ out->u[2] = (uint32_t)oh;
+}
+#endif
+/**
+ * This function simulates SIMD 128-bit left shift by the standard C.
+ * The 128-bit integer given in in is shifted by (shift * 8) bits.
+ * This function simulates the LITTLE ENDIAN SIMD.
+ * @param out the output of this function
+ * @param in the 128-bit data to be shifted
+ * @param shift the shift value
+ */
+#ifdef ONLY64
+inline static void lshift128(w128_t *out, w128_t const *in, int shift) {
+ uint64_t th, tl, oh, ol;
+
+ th = ((uint64_t)in->u[2] << 32) | ((uint64_t)in->u[3]);
+ tl = ((uint64_t)in->u[0] << 32) | ((uint64_t)in->u[1]);
+
+ oh = th << (shift * 8);
+ ol = tl << (shift * 8);
+ oh |= tl >> (64 - shift * 8);
+ out->u[0] = (uint32_t)(ol >> 32);
+ out->u[1] = (uint32_t)ol;
+ out->u[2] = (uint32_t)(oh >> 32);
+ out->u[3] = (uint32_t)oh;
+}
+#else
+inline static void lshift128(w128_t *out, w128_t const *in, int shift) {
+ uint64_t th, tl, oh, ol;
+
+ th = ((uint64_t)in->u[3] << 32) | ((uint64_t)in->u[2]);
+ tl = ((uint64_t)in->u[1] << 32) | ((uint64_t)in->u[0]);
+
+ oh = th << (shift * 8);
+ ol = tl << (shift * 8);
+ oh |= tl >> (64 - shift * 8);
+ out->u[1] = (uint32_t)(ol >> 32);
+ out->u[0] = (uint32_t)ol;
+ out->u[3] = (uint32_t)(oh >> 32);
+ out->u[2] = (uint32_t)oh;
+}
+#endif
+
+/**
+ * This function represents the recursion formula.
+ * @param r output
+ * @param a a 128-bit part of the internal state array
+ * @param b a 128-bit part of the internal state array
+ * @param c a 128-bit part of the internal state array
+ * @param d a 128-bit part of the internal state array
+ */
+#if (!defined(HAVE_ALTIVEC)) && (!defined(HAVE_SSE2))
+#ifdef ONLY64
+inline static void do_recursion(w128_t *r, w128_t *a, w128_t *b, w128_t *c,
+ w128_t *d) {
+ w128_t x;
+ w128_t y;
+
+ lshift128(&x, a, SL2);
+ rshift128(&y, c, SR2);
+ r->u[0] = a->u[0] ^ x.u[0] ^ ((b->u[0] >> SR1) & MSK2) ^ y.u[0]
+ ^ (d->u[0] << SL1);
+ r->u[1] = a->u[1] ^ x.u[1] ^ ((b->u[1] >> SR1) & MSK1) ^ y.u[1]
+ ^ (d->u[1] << SL1);
+ r->u[2] = a->u[2] ^ x.u[2] ^ ((b->u[2] >> SR1) & MSK4) ^ y.u[2]
+ ^ (d->u[2] << SL1);
+ r->u[3] = a->u[3] ^ x.u[3] ^ ((b->u[3] >> SR1) & MSK3) ^ y.u[3]
+ ^ (d->u[3] << SL1);
+}
+#else
+inline static void do_recursion(w128_t *r, w128_t *a, w128_t *b, w128_t *c,
+ w128_t *d) {
+ w128_t x;
+ w128_t y;
+
+ lshift128(&x, a, SL2);
+ rshift128(&y, c, SR2);
+ r->u[0] = a->u[0] ^ x.u[0] ^ ((b->u[0] >> SR1) & MSK1) ^ y.u[0]
+ ^ (d->u[0] << SL1);
+ r->u[1] = a->u[1] ^ x.u[1] ^ ((b->u[1] >> SR1) & MSK2) ^ y.u[1]
+ ^ (d->u[1] << SL1);
+ r->u[2] = a->u[2] ^ x.u[2] ^ ((b->u[2] >> SR1) & MSK3) ^ y.u[2]
+ ^ (d->u[2] << SL1);
+ r->u[3] = a->u[3] ^ x.u[3] ^ ((b->u[3] >> SR1) & MSK4) ^ y.u[3]
+ ^ (d->u[3] << SL1);
+}
+#endif
+#endif
+
+#if (!defined(HAVE_ALTIVEC)) && (!defined(HAVE_SSE2))
+/**
+ * This function fills the internal state array with pseudorandom
+ * integers.
+ */
+inline static void gen_rand_all(void) {
+ int i;
+ w128_t *r1, *r2;
+
+ r1 = &sfmt[N - 2];
+ r2 = &sfmt[N - 1];
+ for (i = 0; i < N - POS1; i++) {
+ do_recursion(&sfmt[i], &sfmt[i], &sfmt[i + POS1], r1, r2);
+ r1 = r2;
+ r2 = &sfmt[i];
+ }
+ for (; i < N; i++) {
+ do_recursion(&sfmt[i], &sfmt[i], &sfmt[i + POS1 - N], r1, r2);
+ r1 = r2;
+ r2 = &sfmt[i];
+ }
+}
+
+/**
+ * This function fills the user-specified array with pseudorandom
+ * integers.
+ *
+ * @param array an 128-bit array to be filled by pseudorandom numbers.
+ * @param size number of 128-bit pseudorandom numbers to be generated.
+ */
+inline static void gen_rand_array(w128_t *array, int size) {
+ int i, j;
+ w128_t *r1, *r2;
+
+ r1 = &sfmt[N - 2];
+ r2 = &sfmt[N - 1];
+ for (i = 0; i < N - POS1; i++) {
+ do_recursion(&array[i], &sfmt[i], &sfmt[i + POS1], r1, r2);
+ r1 = r2;
+ r2 = &array[i];
+ }
+ for (; i < N; i++) {
+ do_recursion(&array[i], &sfmt[i], &array[i + POS1 - N], r1, r2);
+ r1 = r2;
+ r2 = &array[i];
+ }
+ for (; i < size - N; i++) {
+ do_recursion(&array[i], &array[i - N], &array[i + POS1 - N], r1, r2);
+ r1 = r2;
+ r2 = &array[i];
+ }
+ for (j = 0; j < 2 * N - size; j++) {
+ sfmt[j] = array[j + size - N];
+ }
+ for (; i < size; i++, j++) {
+ do_recursion(&array[i], &array[i - N], &array[i + POS1 - N], r1, r2);
+ r1 = r2;
+ r2 = &array[i];
+ sfmt[j] = array[i];
+ }
+}
+#endif
+
+#if defined(BIG_ENDIAN64) && !defined(ONLY64) && !defined(HAVE_ALTIVEC)
+inline static void swap(w128_t *array, int size) {
+ int i;
+ uint32_t x, y;
+
+ for (i = 0; i < size; i++) {
+ x = array[i].u[0];
+ y = array[i].u[2];
+ array[i].u[0] = array[i].u[1];
+ array[i].u[2] = array[i].u[3];
+ array[i].u[1] = x;
+ array[i].u[3] = y;
+ }
+}
+#endif
+/**
+ * This function represents a function used in the initialization
+ * by init_by_array
+ * @param x 32-bit integer
+ * @return 32-bit integer
+ */
+static uint32_t func1(uint32_t x) {
+ return (x ^ (x >> 27)) * (uint32_t)1664525UL;
+}
+
+/**
+ * This function represents a function used in the initialization
+ * by init_by_array
+ * @param x 32-bit integer
+ * @return 32-bit integer
+ */
+static uint32_t func2(uint32_t x) {
+ return (x ^ (x >> 27)) * (uint32_t)1566083941UL;
+}
+
+/**
+ * This function certificate the period of 2^{MEXP}
+ */
+static void period_certification(void) {
+ int inner = 0;
+ int i, j;
+ uint32_t work;
+
+ for (i = 0; i < 4; i++)
+ inner ^= psfmt32[idxof(i)] & parity[i];
+ for (i = 16; i > 0; i >>= 1)
+ inner ^= inner >> i;
+ inner &= 1;
+ /* check OK */
+ if (inner == 1) {
+ return;
+ }
+ /* check NG, and modification */
+ for (i = 0; i < 4; i++) {
+ work = 1;
+ for (j = 0; j < 32; j++) {
+ if ((work & parity[i]) != 0) {
+ psfmt32[idxof(i)] ^= work;
+ return;
+ }
+ work = work << 1;
+ }
+ }
+}
+
+/*----------------
+ PUBLIC FUNCTIONS
+ ----------------*/
+/**
+ * This function returns the identification string.
+ * The string shows the word size, the Mersenne exponent,
+ * and all parameters of this generator.
+ */
+const char *get_idstring(void) {
+ return IDSTR;
+}
+
+/**
+ * This function returns the minimum size of array used for \b
+ * fill_array32() function.
+ * @return minimum size of array used for fill_array32() function.
+ */
+int get_min_array_size32(void) {
+ return N32;
+}
+
+/**
+ * This function returns the minimum size of array used for \b
+ * fill_array64() function.
+ * @return minimum size of array used for fill_array64() function.
+ */
+int get_min_array_size64(void) {
+ return N64;
+}
+
+#ifndef ONLY64
+/**
+ * This function generates and returns 32-bit pseudorandom number.
+ * init_gen_rand or init_by_array must be called before this function.
+ * @return 32-bit pseudorandom number
+ */
+uint32_t gen_rand32(void) {
+ uint32_t r;
+
+ assert(initialized);
+ if (idx >= N32) {
+ gen_rand_all();
+ idx = 0;
+ }
+ r = psfmt32[idx++];
+ return r;
+}
+#endif
+/**
+ * This function generates and returns 64-bit pseudorandom number.
+ * init_gen_rand or init_by_array must be called before this function.
+ * The function gen_rand64 should not be called after gen_rand32,
+ * unless an initialization is again executed.
+ * @return 64-bit pseudorandom number
+ */
+uint64_t gen_rand64(void) {
+#if defined(BIG_ENDIAN64) && !defined(ONLY64)
+ uint32_t r1, r2;
+#else
+ uint64_t r;
+#endif
+
+ assert(initialized);
+ assert(idx % 2 == 0);
+
+ if (idx >= N32) {
+ gen_rand_all();
+ idx = 0;
+ }
+#if defined(BIG_ENDIAN64) && !defined(ONLY64)
+ r1 = psfmt32[idx];
+ r2 = psfmt32[idx + 1];
+ idx += 2;
+ return ((uint64_t)r2 << 32) | r1;
+#else
+ r = psfmt64[idx / 2];
+ idx += 2;
+ return r;
+#endif
+}
+
+#ifndef ONLY64
+/**
+ * This function generates pseudorandom 32-bit integers in the
+ * specified array[] by one call. The number of pseudorandom integers
+ * is specified by the argument size, which must be at least 624 and a
+ * multiple of four. The generation by this function is much faster
+ * than the following gen_rand function.
+ *
+ * For initialization, init_gen_rand or init_by_array must be called
+ * before the first call of this function. This function can not be
+ * used after calling gen_rand function, without initialization.
+ *
+ * @param array an array where pseudorandom 32-bit integers are filled
+ * by this function. The pointer to the array must be \b "aligned"
+ * (namely, must be a multiple of 16) in the SIMD version, since it
+ * refers to the address of a 128-bit integer. In the standard C
+ * version, the pointer is arbitrary.
+ *
+ * @param size the number of 32-bit pseudorandom integers to be
+ * generated. size must be a multiple of 4, and greater than or equal
+ * to (MEXP / 128 + 1) * 4.
+ *
+ * @note \b memalign or \b posix_memalign is available to get aligned
+ * memory. Mac OSX doesn't have these functions, but \b malloc of OSX
+ * returns the pointer to the aligned memory block.
+ */
+void fill_array32(uint32_t *array, int size) {
+ assert(initialized);
+ assert(idx == N32);
+ assert(size % 4 == 0);
+ assert(size >= N32);
+
+ gen_rand_array((w128_t *)array, size / 4);
+ idx = N32;
+}
+#endif
+
+/**
+ * This function generates pseudorandom 64-bit integers in the
+ * specified array[] by one call. The number of pseudorandom integers
+ * is specified by the argument size, which must be at least 312 and a
+ * multiple of two. The generation by this function is much faster
+ * than the following gen_rand function.
+ *
+ * For initialization, init_gen_rand or init_by_array must be called
+ * before the first call of this function. This function can not be
+ * used after calling gen_rand function, without initialization.
+ *
+ * @param array an array where pseudorandom 64-bit integers are filled
+ * by this function. The pointer to the array must be "aligned"
+ * (namely, must be a multiple of 16) in the SIMD version, since it
+ * refers to the address of a 128-bit integer. In the standard C
+ * version, the pointer is arbitrary.
+ *
+ * @param size the number of 64-bit pseudorandom integers to be
+ * generated. size must be a multiple of 2, and greater than or equal
+ * to (MEXP / 128 + 1) * 2
+ *
+ * @note \b memalign or \b posix_memalign is available to get aligned
+ * memory. Mac OSX doesn't have these functions, but \b malloc of OSX
+ * returns the pointer to the aligned memory block.
+ */
+void fill_array64(uint64_t *array, int size) {
+ assert(initialized);
+ assert(idx == N32);
+ assert(size % 2 == 0);
+ assert(size >= N64);
+
+ gen_rand_array((w128_t *)array, size / 2);
+ idx = N32;
+
+#if defined(BIG_ENDIAN64) && !defined(ONLY64)
+ swap((w128_t *)array, size /2);
+#endif
+}
+
+/**
+ * This function initializes the internal state array with a 32-bit
+ * integer seed.
+ *
+ * @param seed a 32-bit integer used as the seed.
+ */
+void init_gen_rand(uint32_t seed) {
+ int i;
+
+ psfmt32[idxof(0)] = seed;
+ for (i = 1; i < N32; i++) {
+ psfmt32[idxof(i)] = 1812433253UL * (psfmt32[idxof(i - 1)]
+ ^ (psfmt32[idxof(i - 1)] >> 30))
+ + i;
+ }
+ idx = N32;
+ period_certification();
+ initialized = 1;
+}
+
+/**
+ * This function initializes the internal state array,
+ * with an array of 32-bit integers used as the seeds
+ * @param init_key the array of 32-bit integers, used as a seed.
+ * @param key_length the length of init_key.
+ */
+void init_by_array(uint32_t *init_key, int key_length) {
+ int i, j, count;
+ uint32_t r;
+ int lag;
+ int mid;
+ int size = N * 4;
+
+ if (size >= 623) {
+ lag = 11;
+ } else if (size >= 68) {
+ lag = 7;
+ } else if (size >= 39) {
+ lag = 5;
+ } else {
+ lag = 3;
+ }
+ mid = (size - lag) / 2;
+
+ memset(sfmt, 0x8b, sizeof(sfmt));
+ if (key_length + 1 > N32) {
+ count = key_length + 1;
+ } else {
+ count = N32;
+ }
+ r = func1(psfmt32[idxof(0)] ^ psfmt32[idxof(mid)]
+ ^ psfmt32[idxof(N32 - 1)]);
+ psfmt32[idxof(mid)] += r;
+ r += key_length;
+ psfmt32[idxof(mid + lag)] += r;
+ psfmt32[idxof(0)] = r;
+
+ count--;
+ for (i = 1, j = 0; (j < count) && (j < key_length); j++) {
+ r = func1(psfmt32[idxof(i)] ^ psfmt32[idxof((i + mid) % N32)]
+ ^ psfmt32[idxof((i + N32 - 1) % N32)]);
+ psfmt32[idxof((i + mid) % N32)] += r;
+ r += init_key[j] + i;
+ psfmt32[idxof((i + mid + lag) % N32)] += r;
+ psfmt32[idxof(i)] = r;
+ i = (i + 1) % N32;
+ }
+ for (; j < count; j++) {
+ r = func1(psfmt32[idxof(i)] ^ psfmt32[idxof((i + mid) % N32)]
+ ^ psfmt32[idxof((i + N32 - 1) % N32)]);
+ psfmt32[idxof((i + mid) % N32)] += r;
+ r += i;
+ psfmt32[idxof((i + mid + lag) % N32)] += r;
+ psfmt32[idxof(i)] = r;
+ i = (i + 1) % N32;
+ }
+ for (j = 0; j < N32; j++) {
+ r = func2(psfmt32[idxof(i)] + psfmt32[idxof((i + mid) % N32)]
+ + psfmt32[idxof((i + N32 - 1) % N32)]);
+ psfmt32[idxof((i + mid) % N32)] ^= r;
+ r -= i;
+ psfmt32[idxof((i + mid + lag) % N32)] ^= r;
+ psfmt32[idxof(i)] = r;
+ i = (i + 1) % N32;
+ }
+
+ idx = N32;
+ period_certification();
+ initialized = 1;
+}
diff --git a/ext/numo/narray/SFMT.h b/ext/numo/narray/SFMT.h
new file mode 100644
index 0000000..7c8b35e
--- /dev/null
+++ b/ext/numo/narray/SFMT.h
@@ -0,0 +1,157 @@
+/**
+ * @file SFMT.h
+ *
+ * @brief SIMD oriented Fast Mersenne Twister(SFMT) pseudorandom
+ * number generator
+ *
+ * @author Mutsuo Saito (Hiroshima University)
+ * @author Makoto Matsumoto (Hiroshima University)
+ *
+ * Copyright (C) 2006, 2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima
+ * University. All rights reserved.
+ *
+ * The new BSD License is applied to this software.
+ * see LICENSE.txt
+ *
+ * @note We assume that your system has inttypes.h. If your system
+ * doesn't have inttypes.h, you have to typedef uint32_t and uint64_t,
+ * and you have to define PRIu64 and PRIx64 in this file as follows:
+ * @verbatim
+ typedef unsigned int uint32_t
+ typedef unsigned long long uint64_t
+ #define PRIu64 "llu"
+ #define PRIx64 "llx"
+ at endverbatim
+ * uint32_t must be exactly 32-bit unsigned integer type (no more, no
+ * less), and uint64_t must be exactly 64-bit unsigned integer type.
+ * PRIu64 and PRIx64 are used for printf function to print 64-bit
+ * unsigned int and 64-bit unsigned int in hexadecimal format.
+ */
+
+#ifndef SFMT_H
+#define SFMT_H
+
+#include <stdio.h>
+
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+ #include <inttypes.h>
+#elif defined(_MSC_VER) || defined(__BORLANDC__)
+ typedef unsigned int uint32_t;
+ typedef unsigned __int64 uint64_t;
+ #define inline __inline
+#else
+ #include <inttypes.h>
+ #if defined(__GNUC__)
+ #define inline __inline__
+ #endif
+#endif
+
+#ifndef PRIu64
+ #if defined(_MSC_VER) || defined(__BORLANDC__)
+ #define PRIu64 "I64u"
+ #define PRIx64 "I64x"
+ #else
+ #define PRIu64 "llu"
+ #define PRIx64 "llx"
+ #endif
+#endif
+
+#if defined(__GNUC__)
+#define ALWAYSINLINE __attribute__((always_inline))
+#else
+#define ALWAYSINLINE
+#endif
+
+#if defined(_MSC_VER)
+ #if _MSC_VER >= 1200
+ #define PRE_ALWAYS __forceinline
+ #else
+ #define PRE_ALWAYS inline
+ #endif
+#else
+ #define PRE_ALWAYS inline
+#endif
+
+uint32_t gen_rand32(void);
+uint64_t gen_rand64(void);
+void fill_array32(uint32_t *array, int size);
+void fill_array64(uint64_t *array, int size);
+void init_gen_rand(uint32_t seed);
+void init_by_array(uint32_t *init_key, int key_length);
+const char *get_idstring(void);
+int get_min_array_size32(void);
+int get_min_array_size64(void);
+
+/* These real versions are due to Isaku Wada */
+/** generates a random number on [0,1]-real-interval */
+inline static double to_real1(uint32_t v)
+{
+ return v * (1.0/4294967295.0);
+ /* divided by 2^32-1 */
+}
+
+/** generates a random number on [0,1]-real-interval */
+inline static double genrand_real1(void)
+{
+ return to_real1(gen_rand32());
+}
+
+/** generates a random number on [0,1)-real-interval */
+inline static double to_real2(uint32_t v)
+{
+ return v * (1.0/4294967296.0);
+ /* divided by 2^32 */
+}
+
+/** generates a random number on [0,1)-real-interval */
+inline static double genrand_real2(void)
+{
+ return to_real2(gen_rand32());
+}
+
+/** generates a random number on (0,1)-real-interval */
+inline static double to_real3(uint32_t v)
+{
+ return (((double)v) + 0.5)*(1.0/4294967296.0);
+ /* divided by 2^32 */
+}
+
+/** generates a random number on (0,1)-real-interval */
+inline static double genrand_real3(void)
+{
+ return to_real3(gen_rand32());
+}
+/** These real versions are due to Isaku Wada */
+
+/** generates a random number on [0,1) with 53-bit resolution*/
+inline static double to_res53(uint64_t v)
+{
+ return v * (1.0/18446744073709551616.0L);
+}
+
+/** generates a random number on [0,1) with 53-bit resolution from two
+ * 32 bit integers */
+inline static double to_res53_mix(uint32_t x, uint32_t y)
+{
+ return to_res53(x | ((uint64_t)y << 32));
+}
+
+/** generates a random number on [0,1) with 53-bit resolution
+ */
+inline static double genrand_res53(void)
+{
+ return to_res53(gen_rand64());
+}
+
+/** generates a random number on [0,1) with 53-bit resolution
+ using 32bit integer.
+ */
+inline static double genrand_res53_mix(void)
+{
+ uint32_t x, y;
+
+ x = gen_rand32();
+ y = gen_rand32();
+ return to_res53_mix(x, y);
+}
+#endif
diff --git a/ext/numo/narray/array.c b/ext/numo/narray/array.c
new file mode 100644
index 0000000..01d7352
--- /dev/null
+++ b/ext/numo/narray/array.c
@@ -0,0 +1,642 @@
+/*
+ array.c
+ Numerical Array Extension for Ruby
+ (C) Copyright 1999-2017 by Masahiro TANAKA
+*/
+#include <ruby.h>
+#include "numo/narray.h"
+
+// mdai: Multi-Dimensional Array Investigation
+typedef struct {
+ size_t shape;
+ VALUE val;
+} na_mdai_item_t;
+
+typedef struct {
+ int capa;
+ na_mdai_item_t *item;
+ int type; // Ruby numeric type - investigated separately
+ VALUE na_type; // NArray type
+ VALUE int_max;
+} na_mdai_t;
+
+// Order of Ruby object.
+enum { NA_NONE, NA_BIT, NA_INT32, NA_INT64, NA_RATIONAL,
+ NA_DFLOAT, NA_DCOMPLEX, NA_ROBJ, NA_NTYPES };
+
+static ID id_begin;
+static ID id_end;
+static ID id_step;
+static ID id_abs;
+static ID id_cast;
+static ID id_le;
+static ID id_Complex;
+
+
+static VALUE
+ na_object_type(int type, VALUE v)
+{
+ static VALUE int32_max = Qnil;
+ if (NIL_P(int32_max))
+ int32_max = ULONG2NUM(2147483647);
+
+ switch(TYPE(v)) {
+
+ case T_TRUE:
+ case T_FALSE:
+ if (type<NA_BIT)
+ return NA_BIT;
+ return type;
+
+#if SIZEOF_LONG == 4
+ case T_FIXNUM:
+ if (type<NA_INT32)
+ return NA_INT32;
+ return type;
+ case T_BIGNUM:
+ if (type<NA_INT64) {
+ v = rb_funcall(v,id_abs,0);
+ if (RTEST(rb_funcall(v,id_le,1,int32_max))) {
+ if (type<NA_INT32)
+ return NA_INT32;
+ } else {
+ return NA_INT64;
+ }
+ }
+ return type;
+
+#elif SIZEOF_LONG == 8
+ case T_FIXNUM:
+ if (type<NA_INT64) {
+ long x = NUM2LONG(v);
+ if (x<0) x=-x;
+ if (x<=2147483647) {
+ if (type<NA_INT32)
+ return NA_INT32;
+ } else {
+ return NA_INT64;
+ }
+ }
+ return type;
+ case T_BIGNUM:
+ if (type<NA_INT64)
+ return NA_INT64;
+ return type;
+#else
+ case T_FIXNUM:
+ case T_BIGNUM:
+ if (type<NA_INT64) {
+ v = rb_funcall(v,id_abs,0);
+ if (RTEST(rb_funcall(v,id_le,1,int32_max))) {
+ if (type<NA_INT32)
+ return NA_INT32;
+ } else {
+ return NA_INT64;
+ }
+ }
+ return type;
+#endif
+
+ case T_FLOAT:
+ if (type<NA_DFLOAT)
+ return NA_DFLOAT;
+ return type;
+
+ case T_NIL:
+ return type;
+
+ default:
+ if (CLASS_OF(v) == rb_const_get( rb_cObject, id_Complex )) {
+ return NA_DCOMPLEX;
+ }
+ }
+ return NA_ROBJ;
+}
+
+
+#define MDAI_ATTR_TYPE(tp,v,attr) \
+ {tp = na_object_type(tp,rb_funcall(v,id_##attr,0));}
+
+static int na_mdai_object_type(int type, VALUE v)
+{
+ if (rb_obj_is_kind_of(v, rb_cRange)) {
+ MDAI_ATTR_TYPE(type,v,begin);
+ MDAI_ATTR_TYPE(type,v,end);
+ } else if (rb_obj_is_kind_of(v, na_cStep)) {
+ MDAI_ATTR_TYPE(type,v,begin);
+ MDAI_ATTR_TYPE(type,v,end);
+ MDAI_ATTR_TYPE(type,v,step);
+ } else {
+ type = na_object_type(type,v);
+ }
+ return type;
+}
+
+
+static na_mdai_t *
+na_mdai_alloc(VALUE ary)
+{
+ int i, n=4;
+ na_mdai_t *mdai;
+
+ mdai = ALLOC(na_mdai_t);
+ mdai->capa = n;
+ mdai->item = ALLOC_N( na_mdai_item_t, n );
+ for (i=0; i<n; i++) {
+ mdai->item[i].shape = 0;
+ mdai->item[i].val = Qnil;
+ }
+ mdai->item[0].val = ary;
+ mdai->type = NA_NONE;
+ mdai->na_type = Qnil;
+
+ return mdai;
+}
+
+static void
+na_mdai_realloc(na_mdai_t *mdai, int n_extra)
+{
+ int i, n;
+
+ i = mdai->capa;
+ mdai->capa += n_extra;
+ n = mdai->capa;
+ REALLOC_N( mdai->item, na_mdai_item_t, n );
+ for (; i<n; i++) {
+ mdai->item[i].shape = 0;
+ mdai->item[i].val = Qnil;
+ }
+}
+
+static void
+na_mdai_free(void *ptr)
+{
+ na_mdai_t *mdai = (na_mdai_t*)ptr;
+ xfree(mdai->item);
+ xfree(mdai);
+}
+
+
+/* investigate ndim, shape, type of Array */
+static int
+na_mdai_investigate(na_mdai_t *mdai, int ndim)
+{
+ ssize_t i;
+ int j;
+ size_t len, length;
+ double dbeg, dstep;
+ VALUE v;
+ VALUE val;
+
+ val = mdai->item[ndim-1].val;
+ len = RARRAY_LEN(val);
+
+ for (i=0; i < RARRAY_LEN(val); i++) {
+ v = RARRAY_AREF(val,i);
+
+ if (TYPE(v) == T_ARRAY) {
+ /* check recursive array */
+ for (j=0; j<ndim; j++) {
+ if (mdai->item[j].val == v)
+ rb_raise(rb_eStandardError,
+ "cannot convert from a recursive Array to NArray");
+ }
+ if ( ndim >= mdai->capa ) {
+ na_mdai_realloc(mdai,4);
+ }
+ mdai->item[ndim].val = v;
+ if ( na_mdai_investigate(mdai,ndim+1) ) {
+ len--; /* Array is empty */
+ }
+ }
+ else
+ if (rb_obj_is_kind_of(v, rb_cRange) || rb_obj_is_kind_of(v, na_cStep)) {
+ nary_step_sequence(v,&length,&dbeg,&dstep);
+ len += length-1;
+ mdai->type = na_mdai_object_type(mdai->type, v);
+ }
+ else if (IsNArray(v)) {
+ int r;
+ narray_t *na;
+ GetNArray(v,na);
+ if ( na->ndim == 0 ) {
+ len--; /* NArray is empty */
+ } else {
+ if ( ndim+na->ndim > mdai->capa ) {
+ na_mdai_realloc(mdai,((na->ndim-1)/4+1)*4);
+ }
+ for ( j=0,r=ndim; j < na->ndim ; j++,r++ ) {
+ if ( mdai->item[r].shape < na->shape[j] )
+ mdai->item[r].shape = na->shape[j];
+ }
+ }
+ // type
+ if (NIL_P(mdai->na_type)) {
+ mdai->na_type = CLASS_OF(v);
+ } else {
+ mdai->na_type = na_upcast(CLASS_OF(v), mdai->na_type);
+ }
+ } else {
+ mdai->type = na_mdai_object_type(mdai->type, v);
+ }
+ }
+
+ if (len==0) return 1; /* this array is empty */
+ if (mdai->item[ndim-1].shape < len) {
+ mdai->item[ndim-1].shape = len;
+ }
+ return 0;
+}
+
+
+static inline int
+na_mdai_ndim(na_mdai_t *mdai)
+{
+ int i;
+ // Dimension
+ for (i=0; i < mdai->capa && mdai->item[i].shape > 0; i++) ;
+ return i;
+}
+
+static inline void
+na_mdai_shape(na_mdai_t *mdai, int ndim, size_t *shape)
+{
+ int i;
+ for (i=0; i<ndim; i++) {
+ shape[i] = mdai->item[i].shape;
+ }
+}
+
+static VALUE
+na_mdai_dtype_numeric(int type)
+{
+ VALUE tp;
+ // DataType
+ switch(type) {
+ case NA_BIT:
+ tp = numo_cBit;
+ break;
+ case NA_INT32:
+ tp = numo_cInt32;
+ break;
+ case NA_INT64:
+ tp = numo_cInt64;
+ break;
+ case NA_DFLOAT:
+ tp = numo_cDFloat;
+ break;
+ case NA_DCOMPLEX:
+ tp = numo_cDComplex;
+ break;
+ case NA_ROBJ:
+ tp = numo_cRObject;
+ break;
+ default:
+ tp = Qnil;
+ }
+ return tp;
+}
+
+static VALUE
+na_mdai_dtype(na_mdai_t *mdai)
+{
+ VALUE tp;
+
+ tp = na_mdai_dtype_numeric(mdai->type);
+
+ if (!NIL_P(mdai->na_type)) {
+ if (NIL_P(tp)) {
+ tp = mdai->na_type;
+ } else {
+ tp = na_upcast(mdai->na_type,tp);
+ }
+ }
+ return tp;
+}
+
+
+static inline VALUE
+update_type(VALUE *ptype, VALUE dtype)
+{
+ if (ptype) {
+ if (*ptype == cNArray || !RTEST(*ptype)) {
+ *ptype = dtype;
+ } else {
+ dtype = *ptype;
+ }
+ }
+ return dtype;
+}
+
+static inline void
+check_subclass_of_narray(VALUE dtype)
+{
+ if (RTEST(rb_obj_is_kind_of(dtype, rb_cClass))) {
+ if (RTEST(rb_funcall(dtype, id_le, 1, cNArray))) {
+ return;
+ }
+ }
+ rb_raise(nary_eCastError, "cannot convert to NArray");
+}
+
+
+static size_t
+na_mdai_memsize(const void *ptr)
+{
+ const na_mdai_t *mdai = (const na_mdai_t*)ptr;
+
+ return sizeof(na_mdai_t) + mdai->capa * sizeof(na_mdai_item_t);
+}
+
+static const rb_data_type_t mdai_data_type = {
+ "Numo::NArray/mdai",
+ {NULL, na_mdai_free, na_mdai_memsize,},
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
+};
+
+
+static void
+na_composition3_ary(VALUE ary, VALUE *ptype, VALUE *pshape, VALUE *pnary)
+{
+ VALUE vmdai;
+ na_mdai_t *mdai;
+ int i, ndim;
+ size_t *shape;
+ VALUE dtype, dshape;
+
+ mdai = na_mdai_alloc(ary);
+ vmdai = TypedData_Wrap_Struct(rb_cData, &mdai_data_type, (void*)mdai);
+ if ( na_mdai_investigate(mdai, 1) ) {
+ // empty
+ dtype = update_type(ptype, numo_cInt32);
+ if (pshape) {
+ *pshape = rb_ary_new3(1, INT2FIX(0));
+ }
+ if (pnary) {
+ check_subclass_of_narray(dtype);
+ shape = ALLOCA_N(size_t, 1);
+ shape[0] = 0;
+ *pnary = nary_new(dtype, 1, shape);
+ }
+ } else {
+ ndim = na_mdai_ndim(mdai);
+ shape = ALLOCA_N(size_t, ndim);
+ na_mdai_shape(mdai, ndim, shape);
+ dtype = update_type(ptype, na_mdai_dtype(mdai));
+ if (pshape) {
+ dshape = rb_ary_new2(ndim);
+ for (i=0; i<ndim; i++) {
+ rb_ary_push(dshape, SIZET2NUM(shape[i]));
+ }
+ *pshape = dshape;
+ }
+ if (pnary) {
+ check_subclass_of_narray(dtype);
+ *pnary = nary_new(dtype, ndim, shape);
+ }
+ }
+ RB_GC_GUARD(vmdai);
+}
+
+
+static void
+na_composition3(VALUE obj, VALUE *ptype, VALUE *pshape, VALUE *pnary)
+{
+ VALUE dtype, dshape;
+
+ if (TYPE(obj) == T_ARRAY) {
+ na_composition3_ary(obj, ptype, pshape, pnary);
+ }
+ else if (RTEST(rb_obj_is_kind_of(obj,rb_cNumeric))) {
+ dtype = na_mdai_dtype_numeric(na_mdai_object_type(NA_NONE, obj));
+ dtype = update_type(ptype, dtype);
+ if (pshape) {
+ *pshape = rb_ary_new();
+ }
+ if (pnary) {
+ check_subclass_of_narray(dtype);
+ *pnary = nary_new(dtype, 0, 0);
+ }
+ }
+ else if (IsNArray(obj)) {
+ int i, ndim;
+ narray_t *na;
+ GetNArray(obj,na);
+ ndim = na->ndim;
+ dtype = update_type(ptype, CLASS_OF(obj));
+ if (pshape) {
+ dshape = rb_ary_new2(ndim);
+ for (i=0; i<ndim; i++) {
+ rb_ary_push(dshape, SIZET2NUM(na->shape[i]));
+ }
+ *pshape = dshape;
+ }
+ if (pnary) {
+ *pnary = nary_new(dtype, ndim, na->shape);
+ }
+ } else {
+ rb_bug("invalid type for md-array: %s", rb_class2name(CLASS_OF(obj)));
+ }
+}
+
+
+static VALUE
+na_s_array_shape(VALUE mod, VALUE ary)
+{
+ VALUE shape;
+
+ if (TYPE(ary) != T_ARRAY) {
+ // 0-dimension
+ return rb_ary_new();
+ }
+ na_composition3(ary, 0, &shape, 0);
+ return shape;
+}
+
+
+/*
+ Generate new unallocated NArray instance with shape and type defined from obj.
+ Numo::NArray.new_like(obj) returns instance whose type is defined from obj.
+ Numo::DFloat.new_like(obj) returns DFloat instance.
+
+ @overload new_like(obj)
+ @param [Numeric,Array,Numo::NArray] obj
+ @return [Numo::NArray]
+ @example
+ Numo::NArray.new_like([[1,2,3],[4,5,6]])
+ => Numo::Int32#shape=[2,3](empty)
+ Numo::DFloat.new_like([[1,2],[3,4]])
+ => Numo::DFloat#shape=[2,2](empty)
+ Numo::NArray.new_like([1,2i,3])
+ => Numo::DComplex#shape=[3](empty)
+*/
+VALUE
+na_s_new_like(VALUE type, VALUE obj)
+{
+ VALUE newary;
+
+ na_composition3(obj, &type, 0, &newary);
+ return newary;
+}
+
+
+VALUE
+na_ary_composition_dtype(VALUE ary)
+{
+ VALUE type = Qnil;
+
+ na_composition3(ary, &type, 0, 0);
+ return type;
+}
+
+static VALUE
+na_s_array_type(VALUE mod, VALUE ary)
+{
+ return na_ary_composition_dtype(ary);
+}
+
+
+/*
+ Generate NArray object. NArray datatype is automatically selected.
+ @overload [](elements)
+ @param [Numeric,Array] elements
+ @return [NArray]
+*/
+static VALUE
+nary_s_bracket(VALUE klass, VALUE ary)
+{
+ VALUE dtype=Qnil;
+
+ if (TYPE(ary)!=T_ARRAY) {
+ rb_bug("Argument is not array");
+ }
+ dtype = na_ary_composition_dtype(ary);
+ check_subclass_of_narray(dtype);
+ return rb_funcall(dtype, id_cast, 1, ary);
+}
+
+
+//VALUE
+//nst_check_compatibility(VALUE self, VALUE ary);
+
+
+/* investigate ndim, shape, type of Array */
+/*
+static int
+na_mdai_for_struct(na_mdai_t *mdai, int ndim)
+{
+ size_t i;
+ int j, r;
+ size_t len;
+ VALUE v;
+ VALUE val;
+ narray_t *na;
+
+ //fprintf(stderr,"ndim=%d\n",ndim); rb_p(mdai->na_type);
+ if (ndim>4) { abort(); }
+ val = mdai->item[ndim].val;
+
+ //fpintf(stderr,"val = "); rb_p(val);
+
+ if (CLASS_OF(val) == mdai->na_type) {
+ GetNArray(val,na);
+ if ( ndim+na->ndim > mdai->capa ) {
+ abort();
+ na_mdai_realloc(mdai,((na->ndim-1)/4+1)*4);
+ }
+ for ( j=0,r=ndim; j < na->ndim; j++,r++ ) {
+ if ( mdai->item[r].shape < na->shape[j] )
+ mdai->item[r].shape = na->shape[j];
+ }
+ return 1;
+ }
+
+ if (TYPE(val) == T_ARRAY) {
+ // check recursive array
+ for (j=0; j<ndim-1; j++) {
+ if (mdai->item[j].val == val)
+ rb_raise(rb_eStandardError,
+ "cannot convert from a recursive Array to NArray");
+ }
+ //fprintf(stderr,"check:"); rb_p(val);
+ // val is a Struct recort
+ if (RTEST( nst_check_compatibility(mdai->na_type, val) )) {
+ //fputs("compati\n",stderr);
+ return 1;
+ }
+ // otherwise, multi-dimention
+ if (ndim >= mdai->capa) {
+ //fprintf(stderr,"exeed capa\n"); abort();
+ na_mdai_realloc(mdai,4);
+ }
+ // finally, multidimension-check
+ len = RARRAY_LEN(val);
+ for (i=0; i < len; i++) {
+ v = RARRAY_AREF(val,i);
+ if (TYPE(v) != T_ARRAY) {
+ //abort();
+ return 0;
+ }
+ }
+ for (i=0; i < len; i++) {
+ v = RARRAY_AREF(val,i);
+ //fprintf(stderr,"check:"); rb_p(v);
+ mdai->item[ndim+1].val = v;
+ if ( na_mdai_for_struct( mdai, ndim+1 ) == 0 ) {
+ //fprintf(stderr,"not struct:"); rb_p(v);
+ //abort();
+ return 0;
+ }
+ }
+ if (mdai->item[ndim].shape < len) {
+ mdai->item[ndim].shape = len;
+ }
+ return 1;
+ }
+
+ //fprintf(stderr,"invalid for struct:"); rb_p(val); abort();
+ return 0;
+}
+*/
+
+
+/*
+VALUE
+na_ary_composition_for_struct(VALUE nstruct, VALUE ary)
+{
+ volatile VALUE vmdai, vnc;
+ na_mdai_t *mdai;
+ na_compose_t *nc;
+
+ mdai = na_mdai_alloc(ary);
+ mdai->na_type = nstruct;
+ vmdai = TypedData_Wrap_Struct(rb_cData, &mdai_data_type, (void*)mdai);
+ na_mdai_for_struct(mdai, 0);
+ nc = na_compose_alloc();
+ vnc = WrapCompose(nc);
+ na_mdai_result(mdai, nc);
+ //fprintf(stderr,"nc->ndim=%d\n",nc->ndim);
+ rb_gc_force_recycle(vmdai);
+ return vnc;
+}
+*/
+
+
+
+void
+Init_nary_array()
+{
+ rb_define_singleton_method(cNArray, "array_shape", na_s_array_shape, 1);
+ rb_define_singleton_method(cNArray, "array_type", na_s_array_type, 1);
+ rb_define_singleton_method(cNArray, "new_like", na_s_new_like, 1);
+
+ rb_define_singleton_method(cNArray, "[]", nary_s_bracket, -2);
+
+ id_begin = rb_intern("begin");
+ id_end = rb_intern("end");
+ id_step = rb_intern("step");
+ id_cast = rb_intern("cast");
+ id_abs = rb_intern("abs");
+ id_le = rb_intern("<=");
+ id_Complex = rb_intern("Complex");
+}
diff --git a/ext/numo/narray/data.c b/ext/numo/narray/data.c
new file mode 100644
index 0000000..7a70a6a
--- /dev/null
+++ b/ext/numo/narray/data.c
@@ -0,0 +1,966 @@
+/*
+ data.c
+ Numerical Array Extension for Ruby
+ (C) Copyright 1999-2017 by Masahiro TANAKA
+*/
+
+#include <ruby.h>
+#include "numo/narray.h"
+#include "numo/template.h"
+
+static VALUE sym_mulsum;
+static ID id_mulsum;
+static ID id_respond_to_p;
+static ID id_store;
+static ID id_swap_byte;
+
+// ---------------------------------------------------------------------
+
+#define LOOP_UNARY_PTR(lp,proc) \
+{ \
+ size_t i; \
+ ssize_t s1, s2; \
+ char *p1, *p2; \
+ size_t *idx1, *idx2; \
+ INIT_COUNTER(lp, i); \
+ INIT_PTR_IDX(lp, 0, p1, s1, idx1); \
+ INIT_PTR_IDX(lp, 1, p2, s2, idx2); \
+ if (idx1) { \
+ if (idx2) { \
+ for (; i--;) { \
+ proc((p1+*idx1), (p2+*idx2)); \
+ idx1++; \
+ idx2++; \
+ } \
+ } else { \
+ for (; i--;) { \
+ proc((p1+*idx1), p2); \
+ idx1++; \
+ p2 += s2; \
+ } \
+ } \
+ } else { \
+ if (idx2) { \
+ for (; i--;) { \
+ proc(p1, (p1+*idx2)); \
+ p1 += s1; \
+ idx2++; \
+ } \
+ } else { \
+ for (; i--;) { \
+ proc(p1, p2); \
+ p1 += s1; \
+ p2 += s2; \
+ } \
+ } \
+ } \
+}
+
+#define m_memcpy(src,dst) memcpy(dst,src,e)
+void
+iter_copy_bytes(na_loop_t *const lp)
+{
+ size_t e;
+ e = lp->args[0].elmsz;
+ LOOP_UNARY_PTR(lp,m_memcpy);
+}
+
+VALUE
+na_copy(VALUE self)
+{
+ VALUE v;
+ ndfunc_arg_in_t ain[1] = {{Qnil,0}};
+ ndfunc_arg_out_t aout[1] = {{INT2FIX(0),0}};
+ ndfunc_t ndf = { iter_copy_bytes, FULL_LOOP, 1, 1, ain, aout };
+
+ v = na_ndloop(&ndf, 1, self);
+ return v;
+}
+
+VALUE
+na_store(VALUE self, VALUE src)
+{
+ return rb_funcall(self,id_store,1,src);
+}
+
+// ---------------------------------------------------------------------
+
+#define m_swap_byte(q1,q2) \
+ { \
+ size_t j; \
+ memcpy(b1,q1,e); \
+ for (j=0; j<e; j++) { \
+ b2[e-1-j] = b1[j]; \
+ } \
+ memcpy(q2,b2,e); \
+ }
+
+static void
+iter_swap_byte(na_loop_t *const lp)
+{
+ char *b1, *b2;
+ size_t e;
+
+ e = lp->args[0].elmsz;
+ b1 = ALLOCA_N(char, e);
+ b2 = ALLOCA_N(char, e);
+ LOOP_UNARY_PTR(lp,m_swap_byte);
+}
+
+static VALUE
+nary_swap_byte(VALUE self)
+{
+ VALUE v;
+ ndfunc_arg_in_t ain[1] = {{Qnil,0}};
+ ndfunc_arg_out_t aout[1] = {{INT2FIX(0),0}};
+ ndfunc_t ndf = { iter_swap_byte, FULL_LOOP|NDF_ACCEPT_BYTESWAP,
+ 1, 1, ain, aout };
+
+ v = na_ndloop(&ndf, 1, self);
+ if (self!=v) {
+ na_copy_flags(self, v);
+ }
+ REVERSE_ENDIAN(v);
+ return v;
+}
+
+
+static VALUE
+nary_to_network(VALUE self)
+{
+ if (TEST_BIG_ENDIAN(self)) {
+ return self;
+ }
+ return rb_funcall(self, id_swap_byte, 0);
+}
+
+static VALUE
+nary_to_vacs(VALUE self)
+{
+ if (TEST_LITTLE_ENDIAN(self)) {
+ return self;
+ }
+ return rb_funcall(self, id_swap_byte, 0);
+}
+
+static VALUE
+nary_to_host(VALUE self)
+{
+ if (TEST_HOST_ORDER(self)) {
+ return self;
+ }
+ return rb_funcall(self, id_swap_byte, 0);
+}
+
+static VALUE
+nary_to_swapped(VALUE self)
+{
+ if (TEST_BYTE_SWAPPED(self)) {
+ return self;
+ }
+ return rb_funcall(self, id_swap_byte, 0);
+}
+
+
+//----------------------------------------------------------------------
+
+static inline int
+check_axis(int axis, int ndim)
+{
+ if (axis < -ndim || axis >= ndim) {
+ rb_raise(nary_eDimensionError,"invalid axis (%d for %d-dimension)",
+ axis, ndim);
+ }
+ if (axis < 0) {
+ axis += ndim;
+ }
+ return axis;
+}
+
+/*
+ Interchange two axes.
+ @overload swapaxes(axis1,axis2)
+ @param [Integer] axis1
+ @param [Integer] axis2
+ @return [Numo::NArray] view of NArray.
+ @example
+ x = Numo::Int32[[1,2,3]]
+
+ p x.swapaxes(0,1)
+ # Numo::Int32(view)#shape=[3,1]
+ # [[1],
+ # [2],
+ # [3]]
+
+ p x = Numo::Int32[[[0,1],[2,3]],[[4,5],[6,7]]]
+ # Numo::Int32#shape=[2,2,2]
+ # [[[0, 1],
+ # [2, 3]],
+ # [[4, 5],
+ # [6, 7]]]
+
+ p x.swapaxes(0,2)
+ # Numo::Int32(view)#shape=[2,2,2]
+ # [[[0, 4],
+ # [2, 6]],
+ # [[1, 5],
+ # [3, 7]]]
+*/
+VALUE
+na_swapaxes(VALUE self, VALUE a1, VALUE a2)
+{
+ int i, j, ndim;
+ size_t tmp_shape;
+ stridx_t tmp_stridx;
+ narray_view_t *na;
+ volatile VALUE view;
+
+ view = na_make_view(self);
+ GetNArrayView(view,na);
+
+ ndim = na->base.ndim;
+ i = check_axis(NUM2INT(a1), ndim);
+ j = check_axis(NUM2INT(a2), ndim);
+
+ tmp_shape = na->base.shape[i];
+ tmp_stridx = na->stridx[i];
+ na->base.shape[i] = na->base.shape[j];
+ na->stridx[i] = na->stridx[j];
+ na->base.shape[j] = tmp_shape;
+ na->stridx[j] = tmp_stridx;
+
+ return view;
+}
+
+VALUE
+na_transpose_map(VALUE self, int *map)
+{
+ int i, ndim;
+ size_t *shape;
+ stridx_t *stridx;
+ narray_view_t *na;
+ volatile VALUE view;
+
+ view = na_make_view(self);
+ GetNArrayView(view,na);
+
+ ndim = na->base.ndim;
+ shape = ALLOCA_N(size_t,ndim);
+ stridx = ALLOCA_N(stridx_t,ndim);
+
+ for (i=0; i<ndim; i++) {
+ shape[i] = na->base.shape[i];
+ stridx[i] = na->stridx[i];
+ }
+ for (i=0; i<ndim; i++) {
+ na->base.shape[i] = shape[map[i]];
+ na->stridx[i] = stridx[map[i]];
+ }
+ return view;
+}
+
+
+#define SWAP(a,b,tmp) {tmp=a;a=b;b=tmp;}
+
+VALUE
+na_transpose(int argc, VALUE *argv, VALUE self)
+{
+ int ndim, *map, *permute;
+ int i, d;
+ bool is_positive, is_negative;
+ narray_t *na1;
+
+ GetNArray(self,na1);
+ ndim = na1->ndim;
+ if (ndim < 2) {
+ if (argc > 0) {
+ rb_raise(rb_eArgError, "unnecessary argument for 1-d array");
+ }
+ return na_make_view(self);
+ }
+ map = ALLOCA_N(int,ndim);
+ if (argc == 0) {
+ for (i=0; i < ndim; i++) {
+ map[i] = ndim-1-i;
+ }
+ return na_transpose_map(self,map);
+ }
+ // with argument
+ if (argc > ndim) {
+ rb_raise(rb_eArgError, "more arguments than ndim");
+ }
+ for (i=0; i < ndim; i++) {
+ map[i] = i;
+ }
+ permute = ALLOCA_N(int,argc);
+ for (i=0; i < argc; i++) {
+ permute[i] = 0;
+ }
+ is_positive = is_negative = 0;
+ for (i=0; i < argc; i++) {
+ if (TYPE(argv[i]) != T_FIXNUM) {
+ rb_raise(rb_eArgError, "invalid argument");
+ }
+ d = FIX2INT(argv[i]);
+ if (d >= 0) {
+ if (d >= argc) {
+ rb_raise(rb_eArgError, "out of dimension range");
+ }
+ if (is_negative) {
+ rb_raise(rb_eArgError, "dimension must be non-negative only or negative only");
+ }
+ if (permute[d]) {
+ rb_raise(rb_eArgError, "not permutation");
+ }
+ map[i] = d;
+ permute[d] = 1;
+ is_positive = 1;
+ } else {
+ if (d < -argc) {
+ rb_raise(rb_eArgError, "out of dimension range");
+ }
+ if (is_positive) {
+ rb_raise(rb_eArgError, "dimension must be non-negative only or negative only");
+ }
+ if (permute[argc+d]) {
+ rb_raise(rb_eArgError, "not permutation");
+ }
+ map[ndim-argc+i] = ndim+d;
+ permute[argc+d] = 1;
+ is_negative = 1;
+ }
+ }
+ return na_transpose_map(self,map);
+}
+
+//----------------------------------------------------------------------
+
+static void
+na_check_reshape(int argc, VALUE *argv, VALUE self, size_t *shape)
+{
+ int i, unfixed=-1;
+ size_t total=1;
+ narray_t *na;
+
+ if (argc == 0) {
+ rb_raise(rb_eArgError, "No argrument");
+ }
+ GetNArray(self,na);
+ if (NA_SIZE(na) == 0) {
+ rb_raise(rb_eRuntimeError, "cannot reshape empty array");
+ }
+
+ /* get shape from argument */
+ for (i=0; i<argc; ++i) {
+ switch(TYPE(argv[i])) {
+ case T_FIXNUM:
+ total *= shape[i] = NUM2INT(argv[i]);
+ break;
+ case T_NIL:
+ case T_TRUE:
+ if (unfixed >= 0) {
+ rb_raise(rb_eArgError,"multiple unfixed dimension");
+ }
+ unfixed = i;
+ break;
+ default:
+ rb_raise(rb_eArgError,"illegal type");
+ }
+ }
+
+ if (unfixed>=0) {
+ if (NA_SIZE(na) % total != 0) {
+ rb_raise(rb_eArgError, "Total size size must be divisor");
+ }
+ shape[unfixed] = NA_SIZE(na) / total;
+ }
+ else if (total != NA_SIZE(na)) {
+ rb_raise(rb_eArgError, "Total size must be same");
+ }
+}
+
+/*
+ Change the shape of self NArray without coping.
+ Raise exception if self is non-contiguous.
+
+ @overload reshape!(size0,size1,...)
+ @param sizeN [Integer] new shape
+ @return [Numo::NArray] return self.
+ @example
+*/
+static VALUE
+na_reshape_bang(int argc, VALUE *argv, VALUE self)
+{
+ size_t *shape;
+ narray_t *na;
+
+ if (na_check_contiguous(self)==Qfalse) {
+ rb_raise(rb_eStandardError, "cannot change shape of non-contiguous NArray");
+ }
+ shape = ALLOCA_N(size_t, argc);
+ na_check_reshape(argc, argv, self, shape);
+
+ GetNArray(self, na);
+ na_setup_shape(na, argc, shape);
+ return self;
+}
+
+/*
+ Copy and change the shape of NArray.
+ Returns a copied NArray.
+
+ @overload reshape(size0,size1,...)
+ @param sizeN [Integer] new shape
+ @return [Numo::NArray] return self.
+ @example
+*/
+static VALUE
+na_reshape(int argc, VALUE *argv, VALUE self)
+{
+ size_t *shape;
+ narray_t *na;
+ VALUE copy;
+
+ shape = ALLOCA_N(size_t, argc);
+ na_check_reshape(argc, argv, self, shape);
+
+ copy = rb_funcall(self, rb_intern("dup"), 0);
+ GetNArray(copy, na);
+ na_setup_shape(na, argc, shape);
+ return copy;
+}
+
+//----------------------------------------------------------------------
+
+VALUE
+na_flatten_dim(VALUE self, int sd)
+{
+ int i, nd, fd;
+ size_t j;
+ size_t *c, *pos, *idx1, *idx2;
+ size_t stride;
+ size_t *shape, size;
+ stridx_t sdx;
+ narray_t *na;
+ narray_view_t *na1, *na2;
+ volatile VALUE view;
+
+ GetNArray(self,na);
+ nd = na->ndim;
+
+ if (nd==0) {
+ return na_make_view(self);
+ }
+ if (sd<0 || sd>=nd) {
+ rb_bug("na_flaten_dim: start_dim (%d) out of range",sd);
+ }
+
+ // new shape
+ shape = ALLOCA_N(size_t,sd+1);
+ for (i=0; i<sd; i++) {
+ shape[i] = na->shape[i];
+ }
+ size = 1;
+ for (i=sd; i<nd; i++) {
+ size *= na->shape[i];
+ }
+ shape[sd] = size;
+
+ // new object
+ view = na_s_allocate_view(CLASS_OF(self));
+ na_copy_flags(self, view);
+ GetNArrayView(view, na2);
+
+ // new stride
+ na_setup_shape((narray_t*)na2, sd+1, shape);
+ na2->stridx = ALLOC_N(stridx_t,sd+1);
+
+ switch(na->type) {
+ case NARRAY_DATA_T:
+ case NARRAY_FILEMAP_T:
+ stride = nary_element_stride(self);
+ for (i=sd+1; i--; ) {
+ //printf("data: i=%d shpae[i]=%ld stride=%ld\n",i,shape[i],stride);
+ SDX_SET_STRIDE(na2->stridx[i],stride);
+ stride *= shape[i];
+ }
+ na2->offset = 0;
+ na2->data = self;
+ break;
+ case NARRAY_VIEW_T:
+ GetNArrayView(self, na1);
+ na2->data = na1->data;
+ na2->offset = na1->offset;
+ for (i=0; i<sd; i++) {
+ if (SDX_IS_INDEX(na1->stridx[i])) {
+ idx1 = SDX_GET_INDEX(na1->stridx[i]);
+ idx2 = ALLOC_N(size_t, shape[i]);
+ for (j=0; j<shape[i]; j++) {
+ idx2[j] = idx1[j];
+ }
+ SDX_SET_INDEX(na2->stridx[i],idx2);
+ } else {
+ na2->stridx[i] = na1->stridx[i];
+ //printf("view: i=%d stridx=%d\n",i,SDX_GET_STRIDE(sdx));
+ }
+ }
+ // flat dimenion == last dimension
+ if (RTEST(na_check_ladder(self,sd))) {
+ //if (0) {
+ na2->stridx[sd] = na1->stridx[nd-1];
+ } else {
+ // set index
+ idx2 = ALLOC_N(size_t, shape[sd]);
+ SDX_SET_INDEX(na2->stridx[sd],idx2);
+ // init for md-loop
+ fd = nd-sd;
+ c = ALLOC_N(size_t, fd);
+ for (i=0; i<fd; i++) c[i]=0;
+ pos = ALLOC_N(size_t, fd+1);
+ pos[0] = 0;
+ // md-loop
+ for (i=j=0;;) {
+ for (; i<fd; i++) {
+ sdx = na1->stridx[i+sd];
+ if (SDX_IS_INDEX(sdx)) {
+ pos[i+1] = pos[i] + SDX_GET_INDEX(sdx)[c[i]];
+ } else {
+ pos[i+1] = pos[i] + SDX_GET_STRIDE(sdx)*c[i];
+ }
+ }
+ idx2[j++] = pos[i];
+ for (;;) {
+ if (i==0) goto loop_end;
+ i--;
+ c[i]++;
+ if (c[i] < na1->base.shape[i+sd]) break;
+ c[i] = 0;
+ }
+ }
+ loop_end:
+ xfree(pos);
+ xfree(c);
+ }
+ break;
+ }
+ return view;
+}
+
+VALUE
+na_flatten(VALUE self)
+{
+ return na_flatten_dim(self,0);
+}
+
+//----------------------------------------------------------------------
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+/*
+ Returns a diagonal view of NArray
+ @overload diagonal([offset,axes])
+ @param [Integer] offset Diagonal offset from the main diagonal.
+ The default is 0. k>0 for diagonals above the main diagonal,
+ and k<0 for diagonals below the main diagonal.
+ @param [Array] axes Array of axes to be used as the 2-d sub-arrays
+ from which the diagonals should be taken. Defaults to last-two
+ axes ([-2,-1]).
+ @return [Numo::NArray] diagonal view of NArray.
+ @example
+ a = Numo::DFloat.new(4,5).seq
+ => Numo::DFloat#shape=[4,5]
+ [[0, 1, 2, 3, 4],
+ [5, 6, 7, 8, 9],
+ [10, 11, 12, 13, 14],
+ [15, 16, 17, 18, 19]]
+ b = a.diagonal(1)
+ => Numo::DFloat(view)#shape=[4]
+ [1, 7, 13, 19]
+ b.store(0)
+ a
+ => Numo::DFloat#shape=[4,5]
+ [[0, 0, 2, 3, 4],
+ [5, 6, 0, 8, 9],
+ [10, 11, 12, 0, 14],
+ [15, 16, 17, 18, 0]]
+ b.store([1,2,3,4])
+ a
+ => Numo::DFloat#shape=[4,5]
+ [[0, 1, 2, 3, 4],
+ [5, 6, 2, 8, 9],
+ [10, 11, 12, 3, 14],
+ [15, 16, 17, 18, 4]]
+ */
+VALUE
+na_diagonal(int argc, VALUE *argv, VALUE self)
+{
+ int i, k, nd;
+ size_t j;
+ size_t *idx0, *idx1, *diag_idx;
+ size_t *shape;
+ size_t diag_size;
+ ssize_t stride, stride0, stride1;
+ narray_t *na;
+ narray_view_t *na1, *na2;
+ VALUE view;
+ VALUE vofs=0, vaxes=0;
+ ssize_t kofs;
+ size_t k0, k1;
+ int ax[2];
+
+ // check arguments
+ if (argc>2) {
+ rb_raise(rb_eArgError,"too many arguments (%d for 0..2)",argc);
+ }
+
+ for (i=0; i<argc; i++) {
+ switch(TYPE(argv[i])) {
+ case T_FIXNUM:
+ if (vofs) {
+ rb_raise(rb_eArgError,"offset is given twice");
+ }
+ vofs = argv[i];
+ break;
+ case T_ARRAY:
+ if (vaxes) {
+ rb_raise(rb_eArgError,"axes-array is given twice");
+ }
+ vaxes = argv[i];
+ break;
+ }
+ }
+
+ if (vofs) {
+ kofs = NUM2SSIZET(vofs);
+ } else {
+ kofs = 0;
+ }
+
+ GetNArray(self,na);
+ nd = na->ndim;
+ if (nd < 2) {
+ rb_raise(nary_eDimensionError,"less than 2-d array");
+ }
+
+ if (vaxes) {
+ if (RARRAY_LEN(vaxes) != 2) {
+ rb_raise(rb_eArgError,"axes must be 2-element array");
+ }
+ ax[0] = NUM2INT(RARRAY_AREF(vaxes,0));
+ ax[1] = NUM2INT(RARRAY_AREF(vaxes,1));
+ if (ax[0]<-nd || ax[0]>=nd || ax[1]<-nd || ax[1]>=nd) {
+ rb_raise(rb_eArgError,"axis out of range:[%d,%d]",ax[0],ax[1]);
+ }
+ if (ax[0]<0) {ax[0] += nd;}
+ if (ax[1]<0) {ax[1] += nd;}
+ if (ax[0]==ax[1]) {
+ rb_raise(rb_eArgError,"same axes:[%d,%d]",ax[0],ax[1]);
+ }
+ } else {
+ ax[0] = nd-2;
+ ax[1] = nd-1;
+ }
+
+ // Diagonal offset from the main diagonal.
+ if (kofs >= 0) {
+ k0 = 0;
+ k1 = kofs;
+ if (k1 >= na->shape[ax[1]]) {
+ rb_raise(rb_eArgError,"invalid diagonal offset(%"SZF"d) for "
+ "last dimension size(%"SZF"d)",kofs,na->shape[ax[1]]);
+ }
+ } else {
+ k0 = -kofs;
+ k1 = 0;
+ if (k0 >= na->shape[ax[0]]) {
+ rb_raise(rb_eArgError,"invalid diagonal offset(=%"SZF"d) for "
+ "last-1 dimension size(%"SZF"d)",kofs,na->shape[ax[0]]);
+ }
+ }
+
+ diag_size = MIN(na->shape[ax[0]]-k0,na->shape[ax[1]]-k1);
+
+ // new shape
+ shape = ALLOCA_N(size_t,nd-1);
+ for (i=k=0; i<nd; i++) {
+ if (i != ax[0] && i != ax[1]) {
+ shape[k++] = na->shape[i];
+ }
+ }
+ shape[k] = diag_size;
+
+ // new object
+ view = na_s_allocate_view(CLASS_OF(self));
+ na_copy_flags(self, view);
+ GetNArrayView(view, na2);
+
+ // new stride
+ na_setup_shape((narray_t*)na2, nd-1, shape);
+ na2->stridx = ALLOC_N(stridx_t, nd-1);
+
+ switch(na->type) {
+ case NARRAY_DATA_T:
+ case NARRAY_FILEMAP_T:
+ na2->offset = 0;
+ na2->data = self;
+ stride = stride0 = stride1 = nary_element_stride(self);
+ for (i=nd,k=nd-2; i--; ) {
+ if (i==ax[1]) {
+ stride1 = stride;
+ if (kofs > 0) {
+ na2->offset = kofs*stride;
+ }
+ } else if (i==ax[0]) {
+ stride0 = stride;
+ if (kofs < 0) {
+ na2->offset = (-kofs)*stride;
+ }
+ } else {
+ SDX_SET_STRIDE(na2->stridx[--k],stride);
+ }
+ stride *= na->shape[i];
+ }
+ SDX_SET_STRIDE(na2->stridx[nd-2],stride0+stride1);
+ break;
+
+ case NARRAY_VIEW_T:
+ GetNArrayView(self, na1);
+ na2->data = na1->data;
+ na2->offset = na1->offset;
+ for (i=k=0; i<nd; i++) {
+ if (i != ax[0] && i != ax[1]) {
+ if (SDX_IS_INDEX(na1->stridx[i])) {
+ idx0 = SDX_GET_INDEX(na1->stridx[i]);
+ idx1 = ALLOC_N(size_t, na->shape[i]);
+ for (j=0; j<na->shape[i]; j++) {
+ idx1[j] = idx0[j];
+ }
+ SDX_SET_INDEX(na2->stridx[k],idx1);
+ } else {
+ na2->stridx[k] = na1->stridx[i];
+ }
+ k++;
+ }
+ }
+ if (SDX_IS_INDEX(na1->stridx[ax[0]])) {
+ idx0 = SDX_GET_INDEX(na1->stridx[ax[0]]);
+ diag_idx = ALLOC_N(size_t, diag_size);
+ if (SDX_IS_INDEX(na1->stridx[ax[1]])) {
+ idx1 = SDX_GET_INDEX(na1->stridx[ax[1]]);
+ for (j=0; j<diag_size; j++) {
+ diag_idx[j] = idx0[j+k0] + idx1[j+k1];
+ }
+ } else {
+ stride1 = SDX_GET_STRIDE(na1->stridx[ax[1]]);
+ for (j=0; j<diag_size; j++) {
+ diag_idx[j] = idx0[j+k0] + stride1*(j+k1);
+ }
+ }
+ SDX_SET_INDEX(na2->stridx[nd-2],diag_idx);
+ } else {
+ stride0 = SDX_GET_STRIDE(na1->stridx[ax[0]]);
+ if (SDX_IS_INDEX(na1->stridx[ax[1]])) {
+ idx1 = SDX_GET_INDEX(na1->stridx[ax[1]]);
+ diag_idx = ALLOC_N(size_t, diag_size);
+ for (j=0; j<diag_size; j++) {
+ diag_idx[j] = stride0*(j+k0) + idx1[j+k1];
+ }
+ SDX_SET_INDEX(na2->stridx[nd-2],diag_idx);
+ } else {
+ stride1 = SDX_GET_STRIDE(na1->stridx[ax[1]]);
+ na2->offset += stride0*k0 + stride1*k1;
+ SDX_SET_STRIDE(na2->stridx[nd-2],stride0+stride1);
+ }
+ }
+ break;
+ }
+ return view;
+}
+
+//----------------------------------------------------------------------
+
+
+#if 0
+#ifdef SWAP
+#undef SWAP
+#endif
+#define SWAP(a,b,t) {t=a;a=b;b=t;}
+
+static VALUE
+na_new_dimension_for_dot(VALUE self, int pos, int len, bool transpose)
+{
+ int i, k, l, nd;
+ size_t j;
+ size_t *idx1, *idx2;
+ size_t *shape;
+ ssize_t stride;
+ narray_t *na;
+ narray_view_t *na1, *na2;
+ size_t shape_n;
+ stridx_t stridx_n;
+ volatile VALUE view;
+
+ GetNArray(self,na);
+ nd = na->ndim;
+
+ view = na_s_allocate_view(CLASS_OF(self));
+
+ na_copy_flags(self, view);
+ GetNArrayView(view, na2);
+
+ // new dimension
+ if (pos < 0) pos += nd;
+ if (pos > nd || pos < 0) {
+ rb_raise(rb_eRangeError,"new dimension is out of range");
+ }
+ nd += len;
+ shape = ALLOCA_N(size_t,nd);
+ na2->stridx = ALLOC_N(stridx_t,nd);
+
+ switch(na->type) {
+ case NARRAY_DATA_T:
+ case NARRAY_FILEMAP_T:
+ i = k = 0;
+ while (i < nd) {
+ if (i == pos && len > 0) {
+ for (l=0; l<len; l++) {
+ shape[i++] = 1;
+ }
+ } else {
+ shape[i++] = na->shape[k++];
+ }
+ }
+ na_setup_shape((narray_t*)na2, nd, shape);
+ stride = nary_element_stride(self);
+ for (i=nd; i--;) {
+ SDX_SET_STRIDE(na2->stridx[i], stride);
+ stride *= shape[i];
+ }
+ na2->offset = 0;
+ na2->data = self;
+ break;
+ case NARRAY_VIEW_T:
+ GetNArrayView(self, na1);
+ i = k = 0;
+ while (i < nd) {
+ if (i == pos && len > 0) {
+ if (SDX_IS_INDEX(na1->stridx[k])) {
+ stride = SDX_GET_INDEX(na1->stridx[k])[0];
+ } else {
+ stride = SDX_GET_STRIDE(na1->stridx[k]);
+ }
+ for (l=0; l<len; l++) {
+ shape[i] = 1;
+ SDX_SET_STRIDE(na2->stridx[i], stride);
+ i++;
+ }
+ } else {
+ shape[i] = na1->base.shape[k];
+ if (SDX_IS_INDEX(na1->stridx[k])) {
+ idx1 = SDX_GET_INDEX(na1->stridx[k]);
+ idx2 = ALLOC_N(size_t,na1->base.shape[k]);
+ for (j=0; j<na1->base.shape[k]; j++) {
+ idx2[j] = idx1[j];
+ }
+ SDX_SET_INDEX(na2->stridx[i], idx2);
+ } else {
+ na2->stridx[i] = na1->stridx[k];
+ }
+ i++; k++;
+ }
+ }
+ na_setup_shape((narray_t*)na2, nd, shape);
+ na2->offset = na1->offset;
+ na2->data = na1->data;
+ break;
+ }
+
+ if (transpose) {
+ SWAP(na2->base.shape[nd-1], na2->base.shape[nd-2], shape_n);
+ SWAP(na2->stridx[nd-1], na2->stridx[nd-2], stridx_n);
+ }
+
+ return view;
+}
+
+
+//----------------------------------------------------------------------
+
+/*
+ * call-seq:
+ * narray.dot(other) => narray
+ *
+ * Returns dot product.
+ *
+ */
+
+static VALUE
+numo_na_dot(VALUE self, VALUE other)
+{
+ VALUE test;
+ volatile VALUE a1=self, a2=other;
+ narray_t *na1, *na2;
+
+ test = rb_funcall(a1, id_respond_to_p, 1, sym_mulsum);
+ if (!RTEST(test)) {
+ rb_raise(rb_eNoMethodError,"requires mulsum method for dot method");
+ }
+ GetNArray(a1,na1);
+ GetNArray(a2,na2);
+ if (na1->ndim==0 || na2->ndim==0) {
+ rb_raise(nary_eDimensionError,"zero dimensional narray");
+ }
+ if (na2->ndim > 1) {
+ if (na1->shape[na1->ndim-1] != na2->shape[na2->ndim-2]) {
+ rb_raise(nary_eShapeError,"shape mismatch: self.shape[-1](=%"SZF"d) != other.shape[-2](=%"SZF"d)",
+ na1->shape[na1->ndim-1], na2->shape[na2->ndim-2]);
+ }
+ // insert new axis [ ..., last-1-dim, newaxis*other.ndim, last-dim ]
+ a1 = na_new_dimension_for_dot(a1, na1->ndim-1, na2->ndim-1, 0);
+ // insert & transpose [ newaxis*self.ndim, ..., last-dim, last-1-dim ]
+ a2 = na_new_dimension_for_dot(a2, 0, na1->ndim-1, 1);
+ }
+ return rb_funcall(a1,id_mulsum,2,a2,INT2FIX(-1));
+}
+#endif
+
+void
+Init_nary_data()
+{
+ rb_define_method(cNArray, "copy", na_copy, 0); // deprecated
+
+ rb_define_method(cNArray, "flatten", na_flatten, 0);
+ rb_define_method(cNArray, "swapaxes", na_swapaxes, 2);
+ rb_define_method(cNArray, "transpose", na_transpose, -1);
+
+ rb_define_method(cNArray, "reshape", na_reshape,-1);
+ rb_define_method(cNArray, "reshape!", na_reshape_bang,-1);
+ /*
+ rb_define_alias(cNArray, "shape=","reshape!");
+ */
+ rb_define_method(cNArray, "diagonal", na_diagonal,-1);
+
+ rb_define_method(cNArray, "swap_byte", nary_swap_byte, 0);
+#ifdef DYNAMIC_ENDIAN
+#else
+#ifdef WORDS_BIGENDIAN
+#else // LITTLE_ENDIAN
+ rb_define_alias(cNArray, "hton", "swap_byte");
+ rb_define_alias(cNArray, "network_order?", "byte_swapped?");
+ rb_define_alias(cNArray, "little_endian?", "host_order?");
+ rb_define_alias(cNArray, "vacs_order?", "host_order?");
+#endif
+#endif
+ rb_define_method(cNArray, "to_network", nary_to_network, 0);
+ rb_define_method(cNArray, "to_vacs", nary_to_vacs, 0);
+ rb_define_method(cNArray, "to_host", nary_to_host, 0);
+ rb_define_method(cNArray, "to_swapped", nary_to_swapped, 0);
+
+ //rb_define_method(cNArray, "dot", numo_na_dot, 1);
+
+ id_mulsum = rb_intern("mulsum");
+ sym_mulsum = ID2SYM(id_mulsum);
+ id_respond_to_p = rb_intern("respond_to?");
+ id_store = rb_intern("store");
+ id_swap_byte = rb_intern("swap_byte");
+}
diff --git a/ext/numo/narray/depend.erb b/ext/numo/narray/depend.erb
new file mode 100644
index 0000000..2a35c76
--- /dev/null
+++ b/ext/numo/narray/depend.erb
@@ -0,0 +1,34 @@
+TAGSRC = \
+ ../../ruby/include/ruby/*.h \
+ ../../ruby/*.c \
+ *.h \
+ types/*.h \
+ *.c \
+ types/*.c
+
+tags : TAGS
+TAGS : $(TAGSRC)
+ etags $(TAGSRC)
+
+doc :
+ yard doc *.c types/*.c
+
+C_TMPL = <%=Dir.glob("gen/tmpl*/*.c").join(" ")%>
+
+COGEN = gen/cogen.rb
+DEPENDS = $(C_TMPL) gen/*.rb
+
+<%
+ type_c = []
+ type_rb = Dir.glob("gen/def/*.rb")
+ type_rb.each do |s|
+ type_c << c = "types/"+File.basename(s,".rb")+".c"
+%>
+<%=c%>: <%=s%> $(DEPENDS)
+ $(MAKEDIRS) $(@D) types
+ ruby $(COGEN) -l -o $@ <%=s%>
+<% end %>
+
+src : <%= type_c.join(" ") %>
+
+CLEANOBJS = *.o */*.o *.bak types/*.c
diff --git a/ext/numo/narray/extconf.rb b/ext/numo/narray/extconf.rb
new file mode 100644
index 0000000..47a7684
--- /dev/null
+++ b/ext/numo/narray/extconf.rb
@@ -0,0 +1,97 @@
+require 'rbconfig.rb'
+require 'mkmf'
+require "erb"
+
+if RUBY_VERSION < "2.0.0"
+ puts "Numo::NArray requires Ruby version 2.0 or later."
+ exit(1)
+end
+
+rm_f 'numo/extconf.h'
+
+#$CFLAGS="-g3 -O0 -Wall"
+#$CFLAGS=" $(cflags) -O3 -m64 -msse2 -funroll-loops"
+#$CFLAGS=" $(cflags) -O3"
+$INCFLAGS = "-Itypes #$INCFLAGS"
+
+$INSTALLFILES = Dir.glob(%w[numo/*.h numo/types/*.h]).map{|x| [x,'$(archdir)'] }
+$INSTALLFILES << ['numo/extconf.h','$(archdir)']
+if /cygwin|mingw/ =~ RUBY_PLATFORM
+ $INSTALLFILES << ['libnarray.a', '$(archdir)']
+end
+
+srcs = %w(
+narray
+array
+step
+index
+ndloop
+data
+types/bit
+types/int8
+types/int16
+types/int32
+types/int64
+types/uint8
+types/uint16
+types/uint32
+types/uint64
+types/sfloat
+types/dfloat
+types/scomplex
+types/dcomplex
+types/robject
+math
+SFMT
+struct
+rand
+)
+
+if have_header("stdbool.h")
+ stdbool = "stdbool.h"
+else
+ stdbool = nil
+end
+
+if have_header("stdint.h")
+ stdint = "stdint.h"
+elsif have_header("sys/types.h")
+ stdint = "sys/types.h"
+else
+ stdint = nil
+end
+
+have_type("bool", stdbool)
+unless have_type("u_int8_t", stdint)
+ have_type("uint8_t",stdint)
+end
+unless have_type("u_int16_t", stdint)
+ have_type("uint16_t",stdint)
+end
+have_type("int32_t", stdint)
+unless have_type("u_int32_t", stdint)
+ have_type("uint32_t",stdint)
+end
+have_type("int64_t", stdint)
+unless have_type("u_int64_t", stdint)
+ have_type("uint64_t", stdint)
+end
+have_func("exp10")
+
+have_var("rb_cComplex")
+
+$objs = srcs.collect{|i| i+".o"}
+
+create_header('numo/extconf.h')
+
+depend_path = File.join(__dir__, "depend")
+File.open(depend_path, "w") do |depend|
+ depend_erb_path = File.join(__dir__, "depend.erb")
+ File.open(depend_erb_path, "r") do |depend_erb|
+ erb = ERB.new(depend_erb.read)
+ erb.filename = depend_erb_path
+ depend.print(erb.result)
+ end
+end
+
+create_makefile('numo/narray')
diff --git a/ext/numo/narray/gen/cogen.rb b/ext/numo/narray/gen/cogen.rb
new file mode 100644
index 0000000..20264c3
--- /dev/null
+++ b/ext/numo/narray/gen/cogen.rb
@@ -0,0 +1,56 @@
+#! /usr/bin/env ruby
+
+thisdir = File.dirname(__FILE__)
+libpath = File.absolute_path(File.dirname(__FILE__))+"/../../../../lib"
+$LOAD_PATH.unshift libpath
+
+require_relative "./narray_def"
+
+while true
+ if ARGV[0] == "-l"
+ require "erbpp/line_number"
+ ARGV.shift
+ elsif ARGV[0] == "-o"
+ ARGV.shift
+ $output = ARGV.shift
+ require "fileutils"
+ FileUtils.rm_f($output)
+ else
+ break
+ end
+end
+
+if ARGV.size != 1
+ puts "usage:\n ruby #{$0} [-l] erb_base [type_file]"
+ exit 1
+end
+
+type_file, = ARGV
+type_name = File.basename(type_file,".rb")
+
+erb_dir = ["tmpl"]
+erb_dir.unshift("tmpl_bit") if (type_name == "bit")
+erb_dir.map!{|d| File.join(thisdir,d)}
+
+code = DefLib.new do
+ set erb_dir: erb_dir
+ set erb_suffix: ".c"
+ set ns_var: "mNumo"
+
+ set file_name: $output||""
+ set include_files: ["numo/types/#{type_name}.h"]
+ set lib_name: "numo_"+type_name
+
+ def_class do
+ extend NArrayMethod
+ extend NArrayType
+ eval File.read(type_file), binding, type_file
+ eval File.read(File.join(thisdir,"spec.rb")), binding, "spec.rb"
+ end
+end.result
+
+if $output
+ open($output,"w").write(code)
+else
+ $stdout.write(code)
+end
diff --git a/ext/numo/narray/gen/def/bit.rb b/ext/numo/narray/gen/def/bit.rb
new file mode 100644
index 0000000..9173546
--- /dev/null
+++ b/ext/numo/narray/gen/def/bit.rb
@@ -0,0 +1,36 @@
+set name: "bit"
+set type_name: "bit"
+set full_class_name: "Numo::Bit"
+set class_name: "Bit"
+set class_alias: nil
+set class_var: "cT"
+set ctype: "BIT_DIGIT"
+
+set has_math: false
+set is_bit: true
+set is_int: false
+set is_unsigned: true
+set is_float: false
+set is_complex: false
+set is_object: false
+set is_real: false
+set is_comparable: false
+set is_double_precision: false
+
+upcast_rb "Integer"
+upcast_rb "Float", "DFloat"
+upcast_rb "Complex", "DComplex"
+
+upcast "RObject", "RObject"
+upcast "DComplex", "DComplex"
+upcast "SComplex", "SComplex"
+upcast "DFloat", "DFloat"
+upcast "SFloat", "SFloat"
+upcast "Int64", "Int64"
+upcast "Int32", "Int32"
+upcast "Int16", "Int16"
+upcast "Int8", "Int8"
+upcast "UInt64", "UInt64"
+upcast "UInt32", "UInt32"
+upcast "UInt16", "UInt16"
+upcast "UInt8", "UInt8"
diff --git a/ext/numo/narray/gen/def/dcomplex.rb b/ext/numo/narray/gen/def/dcomplex.rb
new file mode 100644
index 0000000..7ced724
--- /dev/null
+++ b/ext/numo/narray/gen/def/dcomplex.rb
@@ -0,0 +1,38 @@
+set name: "dcomplex"
+set type_name: "dcomplex"
+set full_class_name: "Numo::DComplex"
+set class_name: "DComplex"
+set class_alias: "Complex64"
+set class_var: "cT"
+set ctype: "dcomplex"
+set real_class_name: "DFloat"
+set real_ctype: "double"
+
+set has_math: true
+set is_bit: false
+set is_int: false
+set is_unsigned: false
+set is_float: true
+set is_real: false
+set is_complex: true
+set is_object: false
+set is_comparable: false
+set is_double_precision: true
+
+upcast_rb "Integer"
+upcast_rb "Float"
+upcast_rb "Complex"
+
+upcast "RObject", "RObject"
+upcast "DComplex", "DComplex"
+upcast "SComplex", "DComplex"
+upcast "DFloat", "DComplex"
+upcast "SFloat", "DComplex"
+upcast "Int64", "DComplex"
+upcast "Int32", "DComplex"
+upcast "Int16", "DComplex"
+upcast "Int8", "DComplex"
+upcast "UInt64", "DComplex"
+upcast "UInt32", "DComplex"
+upcast "UInt16", "DComplex"
+upcast "UInt8", "DComplex"
diff --git a/ext/numo/narray/gen/def/dfloat.rb b/ext/numo/narray/gen/def/dfloat.rb
new file mode 100644
index 0000000..fcbe812
--- /dev/null
+++ b/ext/numo/narray/gen/def/dfloat.rb
@@ -0,0 +1,36 @@
+set name: "dfloat"
+set type_name: "dfloat"
+set full_class_name: "Numo::DFloat"
+set class_name: "DFloat"
+set class_alias: "Float64"
+set class_var: "cT"
+set ctype: "double"
+
+set has_math: true
+set is_bit: false
+set is_int: false
+set is_unsigned: false
+set is_float: true
+set is_complex: false
+set is_object: false
+set is_real: true
+set is_comparable: true
+set is_double_precision: true
+
+upcast_rb "Integer"
+upcast_rb "Float"
+upcast_rb "Complex", "DComplex"
+
+upcast "RObject", "RObject"
+upcast "DComplex", "DComplex"
+upcast "SComplex", "DComplex"
+upcast "DFloat", "DFloat"
+upcast "SFloat", "DFloat"
+upcast "Int64", "DFloat"
+upcast "Int32", "DFloat"
+upcast "Int16", "DFloat"
+upcast "Int8", "DFloat"
+upcast "UInt64", "DFloat"
+upcast "UInt32", "DFloat"
+upcast "UInt16", "DFloat"
+upcast "UInt8", "DFloat"
diff --git a/ext/numo/narray/gen/def/int16.rb b/ext/numo/narray/gen/def/int16.rb
new file mode 100644
index 0000000..99fae54
--- /dev/null
+++ b/ext/numo/narray/gen/def/int16.rb
@@ -0,0 +1,35 @@
+set name: "int16"
+set type_name: "int16"
+set full_class_name: "Numo::Int16"
+set class_name: "Int16"
+set class_var: "cT"
+set ctype: "int16_t"
+
+set has_math: false
+set is_bit: false
+set is_int: true
+set is_unsigned: false
+set is_float: false
+set is_complex: false
+set is_object: false
+set is_real: true
+set is_comparable: true
+set is_double_precision: false
+
+upcast_rb "Integer"
+upcast_rb "Float", "DFloat"
+upcast_rb "Complex", "DComplex"
+
+upcast "RObject", "RObject"
+upcast "DComplex", "DComplex"
+upcast "SComplex", "SComplex"
+upcast "DFloat", "DFloat"
+upcast "SFloat", "SFloat"
+upcast "Int64", "Int64"
+upcast "Int32", "Int32"
+upcast "Int16"
+upcast "Int8"
+upcast "UInt64", "Int64"
+upcast "UInt32", "Int32"
+upcast "UInt16"
+upcast "UInt8"
diff --git a/ext/numo/narray/gen/def/int32.rb b/ext/numo/narray/gen/def/int32.rb
new file mode 100644
index 0000000..dc519b0
--- /dev/null
+++ b/ext/numo/narray/gen/def/int32.rb
@@ -0,0 +1,35 @@
+set name: "int32"
+set type_name: "int32"
+set full_class_name: "Numo::Int32"
+set class_name: "Int32"
+set class_var: "cT"
+set ctype: "int32_t"
+
+set has_math: false
+set is_bit: false
+set is_int: true
+set is_unsigned: false
+set is_float: false
+set is_complex: false
+set is_object: false
+set is_real: true
+set is_comparable: true
+set is_double_precision: false
+
+upcast_rb "Integer"
+upcast_rb "Float", "DFloat"
+upcast_rb "Complex", "DComplex"
+
+upcast "RObject", "RObject"
+upcast "DComplex", "DComplex"
+upcast "SComplex", "SComplex"
+upcast "DFloat", "DFloat"
+upcast "SFloat", "SFloat"
+upcast "Int64", "Int64"
+upcast "Int32"
+upcast "Int16"
+upcast "Int8"
+upcast "UInt64", "Int64"
+upcast "UInt32"
+upcast "UInt16"
+upcast "UInt8"
diff --git a/ext/numo/narray/gen/def/int64.rb b/ext/numo/narray/gen/def/int64.rb
new file mode 100644
index 0000000..221bad2
--- /dev/null
+++ b/ext/numo/narray/gen/def/int64.rb
@@ -0,0 +1,35 @@
+set name: "int64"
+set type_name: "int64"
+set full_class_name: "Numo::Int64"
+set class_name: "Int64"
+set class_var: "cT"
+set ctype: "int64_t"
+
+set has_math: false
+set is_bit: false
+set is_int: true
+set is_unsigned: false
+set is_float: false
+set is_complex: false
+set is_object: false
+set is_real: true
+set is_comparable: true
+set is_double_precision: false
+
+upcast_rb "Integer"
+upcast_rb "Float", "DFloat"
+upcast_rb "Complex", "DComplex"
+
+upcast "RObject", "RObject"
+upcast "DComplex", "DComplex"
+upcast "SComplex", "SComplex"
+upcast "DFloat", "DFloat"
+upcast "SFloat", "SFloat"
+upcast "Int64"
+upcast "Int32"
+upcast "Int16"
+upcast "Int8"
+upcast "UInt64"
+upcast "UInt32"
+upcast "UInt16"
+upcast "UInt8"
diff --git a/ext/numo/narray/gen/def/int8.rb b/ext/numo/narray/gen/def/int8.rb
new file mode 100644
index 0000000..121a205
--- /dev/null
+++ b/ext/numo/narray/gen/def/int8.rb
@@ -0,0 +1,35 @@
+set name: "int8"
+set type_name: "int8"
+set full_class_name: "Numo::Int8"
+set class_name: "Int8"
+set class_var: "cT"
+set ctype: "int8_t"
+
+set has_math: false
+set is_bit: false
+set is_int: true
+set is_unsigned: false
+set is_float: false
+set is_complex: false
+set is_object: false
+set is_real: true
+set is_comparable: true
+set is_double_precision: false
+
+upcast_rb "Integer"
+upcast_rb "Float", "DFloat"
+upcast_rb "Complex", "DComplex"
+
+upcast "RObject", "RObject"
+upcast "DComplex", "DComplex"
+upcast "SComplex", "SComplex"
+upcast "DFloat", "DFloat"
+upcast "SFloat", "SFloat"
+upcast "Int64", "Int64"
+upcast "Int32", "Int32"
+upcast "Int16", "Int16"
+upcast "Int8", "Int8"
+upcast "UInt64", "Int64"
+upcast "UInt32", "Int64"
+upcast "UInt16", "Int32"
+upcast "UInt8", "Int16"
diff --git a/ext/numo/narray/gen/def/robject.rb b/ext/numo/narray/gen/def/robject.rb
new file mode 100644
index 0000000..e0996ca
--- /dev/null
+++ b/ext/numo/narray/gen/def/robject.rb
@@ -0,0 +1,36 @@
+set name: "robject"
+set type_name: "robject"
+set full_class_name: "Numo::RObject"
+set class_name: "RObject"
+set class_var: "cT"
+set ctype: "VALUE"
+set real_class_name: "RObject"
+set real_ctype: "VALUE"
+
+set has_math: false
+set is_bit: false
+set is_int: true
+set is_unsigned: false
+set is_float: true
+set is_real: true
+set is_complex: false
+set is_object: true
+set is_comparable: true
+set is_double_precision: false
+
+upcast_rb "Integer"
+upcast_rb "Float"
+upcast_rb "Complex"
+
+upcast "DComplex", "RObject"
+upcast "SComplex", "RObject"
+upcast "DFloat", "RObject"
+upcast "SFloat", "RObject"
+upcast "Int64", "RObject"
+upcast "Int32", "RObject"
+upcast "Int16", "RObject"
+upcast "Int8", "RObject"
+upcast "UInt64", "RObject"
+upcast "UInt32", "RObject"
+upcast "UInt16", "RObject"
+upcast "UInt8", "RObject"
diff --git a/ext/numo/narray/gen/def/scomplex.rb b/ext/numo/narray/gen/def/scomplex.rb
new file mode 100644
index 0000000..b0ceffb
--- /dev/null
+++ b/ext/numo/narray/gen/def/scomplex.rb
@@ -0,0 +1,38 @@
+set name: "scomplex"
+set type_name: "scomplex"
+set full_class_name: "Numo::SComplex"
+set class_name: "SComplex"
+set class_alias: "Complex32"
+set class_var: "cT"
+set ctype: "Scomplex"
+set real_class_name: "SFloat"
+set real_ctype: "float"
+
+set has_math: true
+set is_bit: false
+set is_int: false
+set is_unsigned: false
+set is_float: true
+set is_real: false
+set is_complex: true
+set is_object: false
+set is_comparable: false
+set is_double_precision: false
+
+upcast_rb "Integer"
+upcast_rb "Float"
+upcast_rb "Complex"
+
+upcast "RObject", "RObject"
+upcast "DComplex", "DComplex"
+upcast "SComplex", "SComplex"
+upcast "DFloat", "DComplex"
+upcast "SFloat", "SComplex"
+upcast "Int64", "SComplex"
+upcast "Int32", "SComplex"
+upcast "Int16", "SComplex"
+upcast "Int8", "SComplex"
+upcast "UInt64", "SComplex"
+upcast "UInt32", "SComplex"
+upcast "UInt16", "SComplex"
+upcast "UInt8", "SComplex"
diff --git a/ext/numo/narray/gen/def/sfloat.rb b/ext/numo/narray/gen/def/sfloat.rb
new file mode 100644
index 0000000..47be181
--- /dev/null
+++ b/ext/numo/narray/gen/def/sfloat.rb
@@ -0,0 +1,36 @@
+set name: "sfloat"
+set type_name: "sfloat"
+set full_class_name: "Numo::SFloat"
+set class_name: "SFloat"
+set class_alias: "Float32"
+set class_var: "cT"
+set ctype: "float"
+
+set has_math: true
+set is_bit: false
+set is_int: false
+set is_unsigned: false
+set is_float: true
+set is_complex: false
+set is_object: false
+set is_real: true
+set is_comparable: true
+set is_double_precision: false
+
+upcast_rb "Integer"
+upcast_rb "Float"
+upcast_rb "Complex", "SComplex"
+
+upcast "RObject", "RObject"
+upcast "DComplex", "DComplex"
+upcast "SComplex", "SComplex"
+upcast "DFloat", "DFloat"
+upcast "SFloat", "SFloat"
+upcast "Int64", "SFloat"
+upcast "Int32", "SFloat"
+upcast "Int16", "SFloat"
+upcast "Int8", "SFloat"
+upcast "UInt64", "SFloat"
+upcast "UInt32", "SFloat"
+upcast "UInt16", "SFloat"
+upcast "UInt8", "SFloat"
diff --git a/ext/numo/narray/gen/def/uint16.rb b/ext/numo/narray/gen/def/uint16.rb
new file mode 100644
index 0000000..83012c6
--- /dev/null
+++ b/ext/numo/narray/gen/def/uint16.rb
@@ -0,0 +1,35 @@
+set name: "uint16"
+set type_name: "uint16"
+set full_class_name: "Numo::UInt16"
+set class_name: "UInt16"
+set class_var: "cT"
+set ctype: "u_int16_t"
+
+set has_math: false
+set is_bit: false
+set is_int: true
+set is_unsigned: true
+set is_float: false
+set is_complex: false
+set is_object: false
+set is_real: true
+set is_comparable: true
+set is_double_precision: false
+
+upcast_rb "Integer"
+upcast_rb "Float", "DFloat"
+upcast_rb "Complex", "DComplex"
+
+upcast "RObject", "RObject"
+upcast "DComplex", "DComplex"
+upcast "SComplex", "SComplex"
+upcast "DFloat", "DFloat"
+upcast "SFloat", "SFloat"
+upcast "Int64", "Int64"
+upcast "Int32", "Int32"
+upcast "Int16", "Int16"
+upcast "Int8", "Int16"
+upcast "UInt64", "UInt64"
+upcast "UInt32", "UInt32"
+upcast "UInt16"
+upcast "UInt8"
diff --git a/ext/numo/narray/gen/def/uint32.rb b/ext/numo/narray/gen/def/uint32.rb
new file mode 100644
index 0000000..1269c4e
--- /dev/null
+++ b/ext/numo/narray/gen/def/uint32.rb
@@ -0,0 +1,35 @@
+set name: "uint32"
+set type_name: "uint32"
+set full_class_name: "Numo::UInt32"
+set class_name: "UInt32"
+set class_var: "cT"
+set ctype: "u_int32_t"
+
+set has_math: false
+set is_bit: false
+set is_int: true
+set is_unsigned: true
+set is_float: false
+set is_complex: false
+set is_object: false
+set is_real: true
+set is_comparable: true
+set is_double_precision: false
+
+upcast_rb "Integer"
+upcast_rb "Float", "DFloat"
+upcast_rb "Complex", "DComplex"
+
+upcast "RObject", "RObject"
+upcast "DComplex", "DComplex"
+upcast "SComplex", "SComplex"
+upcast "DFloat", "DFloat"
+upcast "SFloat", "SFloat"
+upcast "Int64", "Int64"
+upcast "Int32", "Int32"
+upcast "Int16", "Int32"
+upcast "Int8", "Int32"
+upcast "UInt64", "UInt64"
+upcast "UInt32"
+upcast "UInt16"
+upcast "UInt8"
diff --git a/ext/numo/narray/gen/def/uint64.rb b/ext/numo/narray/gen/def/uint64.rb
new file mode 100644
index 0000000..4db9bef
--- /dev/null
+++ b/ext/numo/narray/gen/def/uint64.rb
@@ -0,0 +1,35 @@
+set name: "uint64"
+set type_name: "uint64"
+set full_class_name: "Numo::UInt64"
+set class_name: "UInt64"
+set class_var: "cT"
+set ctype: "u_int64_t"
+
+set has_math: false
+set is_bit: false
+set is_int: true
+set is_unsigned: true
+set is_float: false
+set is_complex: false
+set is_object: false
+set is_real: true
+set is_comparable: true
+set is_double_precision: false
+
+upcast_rb "Integer"
+upcast_rb "Float", "DFloat"
+upcast_rb "Complex", "DComplex"
+
+upcast "RObject", "RObject"
+upcast "DComplex", "DComplex"
+upcast "SComplex", "SComplex"
+upcast "DFloat", "DFloat"
+upcast "SFloat", "SFloat"
+upcast "Int64", "Int64"
+upcast "Int32", "Int64"
+upcast "Int16", "Int64"
+upcast "Int8", "Int64"
+upcast "UInt64"
+upcast "UInt32"
+upcast "UInt16"
+upcast "UInt8"
diff --git a/ext/numo/narray/gen/def/uint8.rb b/ext/numo/narray/gen/def/uint8.rb
new file mode 100644
index 0000000..39ed153
--- /dev/null
+++ b/ext/numo/narray/gen/def/uint8.rb
@@ -0,0 +1,35 @@
+set name: "uint8"
+set type_name: "uint8"
+set full_class_name: "Numo::UInt8"
+set class_name: "UInt8"
+set class_var: "cT"
+set ctype: "u_int8_t"
+
+set has_math: false
+set is_bit: false
+set is_int: true
+set is_unsigned: true
+set is_float: false
+set is_complex: false
+set is_object: false
+set is_real: true
+set is_comparable: true
+set is_double_precision: false
+
+upcast_rb "Integer"
+upcast_rb "Float", "DFloat"
+upcast_rb "Complex", "DComplex"
+
+upcast "RObject", "RObject"
+upcast "DComplex", "DComplex"
+upcast "SComplex", "SComplex"
+upcast "DFloat", "DFloat"
+upcast "SFloat", "SFloat"
+upcast "Int64", "Int64"
+upcast "Int32", "Int32"
+upcast "Int16", "Int16"
+upcast "Int8", "Int8"
+upcast "UInt64", "UInt64"
+upcast "UInt32", "UInt32"
+upcast "UInt16", "UInt16"
+upcast "UInt8"
diff --git a/ext/numo/narray/gen/erbpp2.rb b/ext/numo/narray/gen/erbpp2.rb
new file mode 100644
index 0000000..58b35d7
--- /dev/null
+++ b/ext/numo/narray/gen/erbpp2.rb
@@ -0,0 +1,325 @@
+require "erb"
+
+class ErbPP
+
+ def initialize(parent=nil, erb_base=nil, **opts, &block)
+ @parent = parent
+ @children = []
+ @opts = opts
+ set erb_base: erb_base if erb_base
+ @parent.add_child(self) if @parent
+ instance_eval(&block) if block
+ end
+
+ attr_reader :children
+ attr_accessor :parent
+
+ def add_child(child)
+ @children.push(child)
+ end
+
+ def set(**opts)
+ @opts.merge!(opts)
+ end
+
+ def get(key, *args, &block)
+ if respond_to?(key)
+ return send(key, *args, &block)
+ end
+ if args.empty? && block.nil? && @opts.has_key?(key)
+ return @opts[key]
+ end
+ if @parent
+ return @parent.get(key, *args, &block)
+ end
+ nil
+ end
+
+ def description
+ if s = @opts[:description] || @opts[:desc]
+ s.gsub(/\@\{/,"[").gsub(/\@\}/,"]")
+ end
+ end
+
+ alias desc description
+
+ alias method_missing_alias method_missing
+
+ def method_missing(_meth_id, *args, &block)
+ if args.empty?
+ #$stderr.puts _meth_id.inspect
+ v = get(_meth_id, *args, &block)
+ return v if !v.nil?
+ end
+ method_missing_alias(_meth_id, *args, &block)
+ end
+
+ # ERB Loader
+
+ def load_erb(base_name)
+ safe_level = nil
+ trim_mode = '%<>'
+ file = base_name + get(:erb_suffix)
+ dirs = get(:erb_dir)
+ dirs = [dirs] if !dirs.kind_of?(Array)
+ dirs.each do |x|
+ Dir.glob(x).each do |dir|
+ path = File.join(dir,file)
+ if File.exist?(path)
+ erb = ERB.new(File.read(path), safe_level, trim_mode)
+ erb.filename = path
+ return erb
+ end
+ end
+ end
+ raise "file not found: #{file.inspect} in #{dirs.inspect}"
+ end
+
+ def run
+ if base = @opts[:erb_base]
+ load_erb(base).run(binding)
+ end
+ end
+
+ def result
+ if base = @opts[:erb_base]
+ load_erb(base).result(binding)
+ end
+ end
+
+ def write(output)
+ File.open(output,"wt") do |f|
+ f.print(result)
+ end
+ end
+
+ def init_def
+ end
+
+ def find_tmpl(name)
+ @parent.children.find{|x| x.name == name }
+ end
+
+ def find(name)
+ children.find{|x| x.name == name }
+ end
+end
+
+
+class DefLib < ErbPP
+ def initialize(parent=nil, **opts, &block)
+ opts[:erb_base] ||= 'lib'
+ opts[:include_files] ||= []
+ super(parent, **opts, &block)
+ end
+ def id_assign
+ ids = []
+ @children.each{|c| a=c.get(:id_list); ids.concat(a) if a}
+ ids.sort.uniq.map{|x| "id_#{x[1]} = rb_intern(\"#{x[0]}\");"}
+ end
+ def id_decl
+ ids = []
+ @children.each{|c| a=c.get(:id_list); ids.concat(a) if a}
+ ids.sort.uniq.map{|x| "static ID id_#{x[1]};\n"}
+ end
+ def def_class(**opts, &block)
+ DefClass.new(self, **opts, &block)
+ end
+ def def_module(**opts, &block)
+ DefModule.new(self, **opts, &block)
+ end
+end
+
+module DeclMethod
+ def def_alloc_func(m, erb_path=nil, **opts, &block)
+ DefAllocFunc.new(self, erb_path||m, name:m, singleton:true, **opts, &block)
+ end
+ def undef_alloc_func
+ UndefAllocFunc.new(self)
+ end
+ def def_method(m, erb_path=nil, **opts, &block)
+ DefMethod.new(self, erb_path||m, name:m, **opts, &block)
+ end
+ def undef_method(m)
+ UndefMethod.new(self,name:m)
+ end
+ def def_singleton_method(m, erb_path=nil, **opts, &block)
+ DefMethod.new(self, erb_path||m, name:m, singleton:true, **opts, &block)
+ end
+ def undef_singleton_method(m)
+ UndefSingletonMethod.new(self,name:m)
+ end
+ def def_module_function(m, erb_path=nil, **opts, &block)
+ DefModuleFunction.new(self, erb_path||m, name:m, **opts, &block)
+ end
+ def def_alias(from, to)
+ DefAlias.new(self, from:from, to:to)
+ end
+ def def_const(m, v, **opts, &block)
+ DefConst.new(self, name:m, value:v, **opts, &block)
+ end
+end
+
+class DefModule < ErbPP
+ include DeclMethod
+ def initialize(parent, **opts, &block)
+ eb = opts[:erb_base] || 'module'
+ super(parent, erb_base:eb, **opts, &block)
+ end
+ def id_list
+ @id_list ||= []
+ end
+ def def_id(name,var=nil)
+ var = name.gsub(/\?/,"_p").gsub(/\!/,"_bang") if var.nil?
+ id_list << [name,var]
+ end
+ def init_def
+ load_erb(init_erb).result(binding)
+ end
+ def init_erb
+ @opts[:init_erb] || "init_module"
+ end
+ def method_code
+ @children.map{|c| c.result}.join("\n")
+ end
+ def _mod_var
+ @opts[:module_var]
+ end
+end
+
+class DefClass < DefModule
+ def initialize(parent, **opts, &block)
+ eb = opts[:erb_base] || 'class'
+ super(parent, erb_base:eb, **opts, &block)
+ end
+ def _mod_var
+ @opts[:class_var]
+ end
+ def init_erb
+ @opts[:init_erb] || "init_class"
+ end
+ def super_class
+ @opts[:super_class] || "rb_cObject"
+ end
+ def free_func
+ @opts[:free_func] || "gsl_"+get(:name)+"_free"
+ end
+end
+
+class DefMethod < ErbPP
+ include DeclMethod
+
+ def initialize(parent, erb_base, **opts, &block)
+ super(parent, **opts, &block)
+ set erb_base: erb_base
+ end
+
+ def id_op
+ if op.size == 1
+ "'#{op}'"
+ else
+ "id_#{c_name}"
+ end
+ end
+
+ def c_name
+ @opts[:name].gsub(/\?/,"_p").gsub(/\!/,"_bang").gsub(/=/,"_set")
+ end
+
+ def op_map
+ @opts[:op] || @opts[:name]
+ end
+
+ def c_func(n_arg=nil)
+ set n_arg: n_arg if n_arg
+ s = (singleton) ? "_s" : ""
+ "#{@parent.name}#{s}_#{c_name}"
+ end
+
+ def c_iter
+ "iter_#{c_func}"
+ end
+
+ def define_method_args
+ "#{_mod_var}, \"#{op_map}\", #{c_func}, #{n_arg}"
+ end
+
+ def init_def
+ return if n_arg == :nodef
+ s = (singleton) ? "_singleton" : ""
+ "rb_define#{s}_method(#{define_method_args});"
+ end
+
+ def singleton
+ @opts[:singleton]
+ end
+end
+
+class DefModuleFunction < DefMethod
+ def initialize(parent, erb_base, **opts, &block)
+ super(parent, erb_base, **opts, &block)
+ set singleton: true
+ end
+
+ def init_def
+ return if n_arg == :nodef
+ "rb_define_module_function(#{define_method_args});"
+ end
+end
+
+class DefAlias < ErbPP
+ def init_def
+ "rb_define_alias(#{_mod_var}, \"#{from}\", \"#{to}\");"
+ end
+end
+
+class DefAllocFunc < DefMethod
+ def init_def
+ "rb_define_alloc_func(#{_mod_var}, #{c_func});"
+ end
+end
+
+class UndefAllocFunc < ErbPP
+ def init_def
+ "rb_undef_alloc_func(#{_mod_var});"
+ end
+end
+
+class UndefMethod < ErbPP
+ def init_def
+ "rb_undef_method(#{_mod_var},\"#{name}\");"
+ end
+end
+
+class UndefSingletonMethod < ErbPP
+ def init_def
+ "rb_undef_method(rb_singleton_class(#{_mod_var}),\"#{name}\");"
+ end
+end
+
+class DefConst < ErbPP
+ def init_def
+ "/*#{desc}*/
+ rb_define_const(#{_mod_var},\"#{name}\",#{value});"
+ end
+end
+
+class DefStruct < ErbPP
+ def method_code
+ "static VALUE #{class_var};"
+ end
+ def init_def
+ items = members.map{|s| "\"#{s}\""}.join(",")
+ "/*#{description}*/
+ #{class_var} = rb_struct_define(\"#{class_name}\",#{items},NULL);"
+ end
+end
+
+class DefInclueModule < ErbPP
+ def initialize(parent=nil, incl_class, incl_module, **opts, &block)
+ super(parent,incl_class:incl_class,incl_module:incl_module,**opts,&block)
+ end
+ def init_def
+ "rb_include_module(#{get(:incl_class)}, #{get(:incl_module)});"
+ end
+end
diff --git a/ext/numo/narray/gen/narray_def.rb b/ext/numo/narray/gen/narray_def.rb
new file mode 100644
index 0000000..1f5278c
--- /dev/null
+++ b/ext/numo/narray/gen/narray_def.rb
@@ -0,0 +1,252 @@
+require_relative './erbpp2'
+
+module NArrayMethod
+
+ def binary(meth, ope=nil)
+ ope = meth if ope.nil?
+ def_method(meth, "binary", op:ope)
+ end
+
+ def binary2(meth, ope=nil)
+ ope = meth if ope.nil?
+ def_method(meth, "binary2", op:ope)
+ end
+
+ def unary(meth, ope=nil)
+ def_method(meth, "unary", op:ope)
+ end
+
+ def pow
+ def_method("pow", "pow", op:"**")
+ end
+
+ def unary2(meth, dtype, result_class)
+ h = {dtype:dtype, result_class:result_class}
+ def_method(meth, "unary2", **h)
+ end
+
+ def set2(meth, dtype, result_class)
+ h = {dtype:dtype, result_class:result_class}
+ def_method(meth, "set2", h)
+ end
+
+ def cond_binary(meth,op=nil)
+ op = meth unless op
+ def_method(meth, "cond_binary", op:op)
+ end
+
+ def cond_unary(meth)
+ def_method(meth, "cond_unary")
+ end
+
+ def bit_count(meth)
+ def_method(meth, "bit_count")
+ end
+
+ def bit_reduce(meth, init_bit)
+ h = {init_bit:init_bit}
+ def_method(meth, "bit_reduce", **h)
+ end
+
+ def accum(meth, dtype, result_class)
+ h = {dtype:dtype, result_class:result_class}
+ def_method(meth, "accum", **h)
+ end
+
+ def accum_index(meth)
+ def_method(meth, "accum_index")
+ end
+
+ def cum(meth, cmacro)
+ def_method(meth, "cum", cmacro:cmacro)
+ end
+
+ def accum_binary(meth, ope=nil)
+ ope = meth if ope.nil?
+ def_method(meth, "accum_binary", op:ope)
+ end
+
+ def qsort(type_name, dtype, dcast, suffix="")
+ h = {type_name:type_name, dtype:dtype, dcast:dcast, suffix:suffix}
+ def_method("qsort", **h)
+ end
+end
+
+module NMathMethod
+
+ def math(meth, n=1, tmpl=nil, **h)
+ if tmpl.nil?
+ case n
+ when 1
+ tmpl = "unary_s"
+ when 2
+ tmpl = "binary_s"
+ when 3
+ tmpl = "ternary_s"
+ else
+ raise "invalid n=#{n}"
+ end
+ end
+ def_module_function(meth, tmpl, **h)
+ end
+end
+
+# ----------------------------------------------------------------------
+
+module NArrayType
+
+ def type_name
+ @opts[:type_name] ||= class_name.downcase
+ end
+ alias tp type_name
+
+ def type_var
+ @opts[:type_var] ||= "numo_c"+class_name
+ end
+
+ def math_var
+ @opts[:math_var] ||= "numo_m"+class_name+"Math"
+ end
+
+ def real_class_name(arg=nil)
+ if arg.nil?
+ @opts[:real_class_name] ||= class_name
+ else
+ @opts[:real_class_name] = arg
+ end
+ end
+
+ def real_ctype(arg=nil)
+ if arg.nil?
+ @opts[:real_ctype] ||= ctype
+ else
+ @opts[:real_ctype] = arg
+ end
+ end
+
+ def real_type_var
+ @opts[:real_type_var] ||= "numo_c"+real_class_name
+ end
+
+ def real_type_name
+ @opts[:real_type_name] ||= real_class_name.downcase
+ end
+
+ def class_alias(*args)
+ case a = @opts[:class_alias]
+ when Array
+ when nil
+ a = @opts[:class_alias] = []
+ else
+ a = @opts[:class_alias] = [a]
+ end
+ a.concat(args)
+ end
+
+ def upcast(c=nil,t=nil)
+ @opts[:upcast] ||= []
+ if c
+ if t
+ t = "numo_c#{t}"
+ else
+ t = "cT"
+ end
+ @opts[:upcast] << "rb_hash_aset(hCast, numo_c#{c}, #{t});"
+ else
+ @opts[:upcast]
+ end
+ end
+
+ def upcast_rb(c,t=nil)
+ @opts[:upcast] ||= []
+ if t
+ t = "numo_c#{t}"
+ else
+ t = "cT"
+ end
+ if c=="Integer"
+ @opts[:upcast] << "#ifdef RUBY_INTEGER_UNIFICATION"
+ @opts[:upcast] << "rb_hash_aset(hCast, rb_cInteger, #{t});"
+ @opts[:upcast] << "#else"
+ @opts[:upcast] << "rb_hash_aset(hCast, rb_cFixnum, #{t});"
+ @opts[:upcast] << "rb_hash_aset(hCast, rb_cBignum, #{t});"
+ @opts[:upcast] << "#endif"
+ else
+ @opts[:upcast] << "rb_hash_aset(hCast, rb_c#{c}, #{t});"
+ end
+ end
+end
+
+# ----------------------------------------------------------------------
+
+module StoreFrom
+
+ def store_from(cname, dtype=nil, macro=nil)
+ tmpl = (cname=="Bit") ? "store_bit" : "store_from"
+ h = { name:cname.downcase,
+ type_name:cname,
+ type_var:"numo_c"+cname,
+ dtype:dtype,
+ macro:macro }
+ Store.new(self, tmpl, **h)
+ end
+
+ def store_numeric
+ StoreNum.new(self, "store_numeric", name:"numeric")
+ end
+
+ def store_array
+ StoreArray.new(self, "store_array", name:"array")
+ end
+
+ def definitions
+ a = []
+ @children.each do |x|
+ if x.condition("")
+ if x.get(:type_name) == parent.class_name
+ a.unshift(x)
+ else
+ a.push(x)
+ end
+ end
+ end
+ a
+ end
+end
+
+# ----------------------------------------------------------------------
+
+class Store < DefMethod
+ def c_func(n=nil)
+ "#{parent.parent.name}_store_#{name}"
+ end
+
+ def condition(klass)
+ "#{klass}==#{type_var}"
+ end
+
+ def extract_data(ptr,pos,x)
+ case type_name
+ when "Bit"
+ "{BIT_DIGIT b; LOAD_BIT(#{ptr},#{pos},b); x = m_from_real(b);}"
+ when "RObject"
+ "#{x} = m_num_to_data(*(#{dtype}*)(#{ptr}+#{pos}))"
+ when /Complex/
+ "{#{dtype} *p = (#{dtype}*)(#{ptr}+#{pos}); #{x} = c_new(REAL(*p),IMAG(*p));}"
+ else
+ "#{x} = m_from_real(*(#{dtype}*)(#{ptr}+#{pos}))"
+ end
+ end
+end
+
+class StoreNum < Store
+ def condition(klass)
+ "IS_INTEGER_CLASS(#{klass}) || #{klass}==rb_cFloat || #{klass}==rb_cComplex"
+ end
+end
+
+class StoreArray < Store
+ def condition(klass)
+ "#{klass}==rb_cArray"
+ end
+end
diff --git a/ext/numo/narray/gen/spec.rb b/ext/numo/narray/gen/spec.rb
new file mode 100644
index 0000000..6b1e9d4
--- /dev/null
+++ b/ext/numo/narray/gen/spec.rb
@@ -0,0 +1,396 @@
+def_id "cast"
+def_id "eq"
+def_id "ne"
+def_id "pow"
+def_id "mulsum"
+if is_complex
+ def_id "real"
+ def_id "imag"
+else
+ def_id "divmod"
+end
+if is_float
+ def_id "nearly_eq"
+ def_id "copysign"
+end
+if is_int
+ def_id "<<","left_shift"
+ def_id ">>","right_shift"
+end
+if is_comparable && !is_object
+ def_id "gt"
+ def_id "ge"
+ def_id "lt"
+ def_id "le"
+end
+if is_object
+ def_id "bit_and"
+ def_id "bit_or"
+ def_id "bit_xor"
+ def_id "bit_not"
+ def_id "abs"
+ def_id "minus"
+ def_id "reciprocal"
+ def_id "square"
+ def_id "floor"
+ def_id "round"
+ def_id "ceil"
+ def_id "truncate"
+ def_id "nan?"
+ def_id "infinite?"
+ def_id "finite?"
+ def_id "==","eq"
+ def_id "!=","ne"
+ def_id ">" ,"gt"
+ def_id ">=","ge"
+ def_id "<" ,"lt"
+ def_id "<=","le"
+ def_id "<=>","ufo"
+end
+
+if is_int && !is_object
+ def_id "minlength" # for bincount
+end
+
+# Constatnts
+
+if is_bit
+ def_const "ELEMENT_BIT_SIZE", "INT2FIX(1)"
+ def_const "ELEMENT_BYTE_SIZE", "rb_float_new(1.0/8)"
+ def_const "CONTIGUOUS_STRIDE", "INT2FIX(1)"
+else
+ def_const "ELEMENT_BIT_SIZE", "INT2FIX(sizeof(dtype)*8)"
+ def_const "ELEMENT_BYTE_SIZE", "INT2FIX(sizeof(dtype))"
+ def_const "CONTIGUOUS_STRIDE", "INT2FIX(sizeof(dtype))"
+end
+
+if !is_object
+ if is_float
+ def_const "EPSILON", "M_EPSILON"
+ end
+ if is_float || is_int
+ def_const "MAX", "M_MAX"
+ def_const "MIN", "M_MIN"
+ end
+end
+
+# Un-define
+
+if is_object
+ undef_singleton_method "from_binary"
+ undef_method "to_binary"
+ undef_method "swap_byte"
+ undef_method "to_network"
+ undef_method "to_vacs"
+ undef_method "to_host"
+ undef_method "to_swapped"
+end
+
+# Allocation
+
+def_alloc_func "alloc_func"
+def_method "allocate"
+
+# Type conversion
+
+def_method "extract"
+def_method "new_dim0"
+
+def_method "store" do
+ extend StoreFrom
+ store_numeric
+ store_from "Bit"
+ if is_complex
+ store_from "DComplex","dcomplex","m_from_dcomplex"
+ store_from "SComplex","scomplex","m_from_scomplex"
+ end
+ store_from "DFloat","double", "m_from_real"
+ store_from "SFloat","float", "m_from_real"
+ store_from "Int64", "int64_t", "m_from_real"
+ store_from "Int32", "int32_t", "m_from_real"
+ store_from "Int16", "int16_t", "m_from_real"
+ store_from "Int8", "int8_t", "m_from_real"
+ store_from "UInt64","u_int64_t","m_from_real"
+ store_from "UInt32","u_int32_t","m_from_real"
+ store_from "UInt16","u_int16_t","m_from_real"
+ store_from "UInt8", "u_int8_t", "m_from_real"
+ store_from "RObject", "VALUE", "m_num_to_data"
+ store_array
+end
+
+def_method "extract_data"
+
+def_method "cast_array"
+def_singleton_method "cast"
+
+def_method "aref", op:"[]"
+def_method "aset", op:"[]="
+
+def_method "coerce_cast"
+def_method "to_a"
+def_method "fill"
+def_method "format"
+def_method "format_to_a"
+def_method "inspect"
+
+
+# Array manipulation
+
+def_method "each"
+unary "map" if !is_bit
+def_method "each_with_index"
+
+if is_bit
+ unary "copy"
+ unary "not", "~"
+ binary "and", "&"
+ binary "or" , "|"
+ binary "xor", "^"
+ binary "eq"
+ bit_count "count_true"
+ def_alias "count_1","count_true"
+ def_alias "count","count_true"
+ bit_count "count_false"
+ def_alias "count_0","count_false"
+ bit_reduce "all?", 1
+ bit_reduce "any?", 0
+ def_method "none?", "none_p"
+ def_method "where"
+ def_method "where2"
+ def_method "mask"
+else
+
+def_method "map_with_index"
+
+# Arithmetic
+
+unary2 "abs", "rtype", "cRT"
+
+binary "add", "+"
+binary "sub", "-"
+binary "mul", "*"
+binary "div", "/"
+
+if !is_complex
+ binary "mod", "%"
+ binary2 "divmod"
+end
+
+pow
+
+unary "minus", "-@"
+unary "reciprocal"
+unary "sign"
+unary "square"
+
+# Complex
+
+if is_complex
+ unary "conj"
+ unary "im"
+ unary2 "real", "rtype", "cRT"
+ unary2 "imag", "rtype", "cRT"
+ unary2 "arg", "rtype", "cRT"
+ def_alias "angle","arg"
+ set2 "set_imag", "rtype", "cRT"
+ set2 "set_real", "rtype", "cRT"
+ def_alias "imag=","set_imag"
+ def_alias "real=","set_real"
+else
+ def_alias "conj", "view"
+ def_alias "im", "view"
+end
+
+def_alias "conjugate","conj"
+
+# base_cond
+
+cond_binary "eq"
+cond_binary "ne"
+
+# nearly_eq : x=~y is true if |x-y| <= (|x|+|y|)*epsilon
+if is_float
+ cond_binary "nearly_eq"
+else
+ def_alias "nearly_eq", "eq"
+end
+def_alias "close_to", "nearly_eq"
+
+# Integer
+if is_int
+ binary "bit_and", "&"
+ binary "bit_or" , "|"
+ binary "bit_xor", "^"
+ unary "bit_not", "~"
+ binary "left_shift", "<<"
+ binary "right_shift", ">>"
+ if !is_object
+ def_alias "floor", "view"
+ def_alias "round", "view"
+ def_alias "ceil", "view"
+ def_alias "trunc", "view"
+ def_alias "rint", "view"
+ end
+end
+
+if is_float
+ unary "floor"
+ unary "round"
+ unary "ceil"
+ unary "trunc"
+ if !is_object
+ unary "rint"
+ binary "copysign"
+ if !is_complex
+ cond_unary "signbit"
+ def_method "modf", "unary_ret2"
+ end
+ end
+end
+
+if is_comparable
+ cond_binary "gt"
+ cond_binary "ge"
+ cond_binary "lt"
+ cond_binary "le"
+ def_alias ">", "gt"
+ def_alias ">=","ge"
+ def_alias "<", "lt"
+ def_alias "<=","le"
+ def_method "clip"
+end
+
+# Float
+
+if is_float
+ cond_unary "isnan"
+ cond_unary "isinf"
+ cond_unary "isposinf"
+ cond_unary "isneginf"
+ cond_unary "isfinite"
+end
+
+accum "sum","dtype","cT"
+accum "prod","dtype","cT"
+if is_double_precision
+ accum "kahan_sum","dtype","cT"
+end
+
+if is_float
+ accum "mean","dtype","cT"
+ accum "stddev","rtype","cRT"
+ accum "var","rtype","cRT"
+ accum "rms","rtype","cRT"
+end
+
+if is_comparable
+ accum "min","dtype","cT"
+ accum "max","dtype","cT"
+ accum "ptp","dtype","cT"
+ accum_index "max_index"
+ accum_index "min_index"
+ def_method "minmax"
+end
+
+if is_int && !is_object
+ def_method "bincount"
+end
+
+cum "cumsum","add"
+cum "cumprod","mul"
+
+# dot
+accum_binary "mulsum"
+
+# rmsdev
+# prod
+
+# shuffle
+# histogram
+
+def_method "seq"
+if is_float
+ def_method "logseq"
+end
+def_method "eye"
+def_alias "indgen", "seq"
+
+def_method "rand"
+if is_float && !is_object
+ def_method "rand_norm"
+end
+
+# y = a[0] + a[1]*x + a[2]*x^2 + a[3]*x^3 + ... + a[n]*x^n
+def_method "poly"
+
+if is_comparable && !is_object
+ if is_float
+ qsort type_name,"dtype","*(dtype*)","_prnan"
+ qsort type_name,"dtype","*(dtype*)","_ignan"
+ else
+ qsort type_name,"dtype","*(dtype*)"
+ end
+ def_method "sort"
+ if is_float
+ qsort type_name+"_index","dtype*","**(dtype**)","_prnan"
+ qsort type_name+"_index","dtype*","**(dtype**)","_ignan"
+ else
+ qsort type_name+"_index","dtype*","**(dtype**)"
+ end
+ def_method "sort_index"
+ def_method "median"
+end
+
+# Math
+# histogram
+
+if has_math
+fn = get(:full_class_name)
+cn = get(:class_name)
+nm = get(:name)
+is_c = is_complex
+
+def_module do
+ extend NMathMethod
+ set ns_var: "cT"
+ set class_name: cn
+ set name: "#{nm}_math"
+ set full_module_name: fn+"::NMath"
+ set module_name: "Math"
+ set module_var: "mTM"
+
+ math "sqrt"
+ math "cbrt"
+ math "log"
+ math "log2"
+ math "log10"
+ math "exp"
+ math "exp2"
+ math "exp10"
+ math "sin"
+ math "cos"
+ math "tan"
+ math "asin"
+ math "acos"
+ math "atan"
+ math "sinh"
+ math "cosh"
+ math "tanh"
+ math "asinh"
+ math "acosh"
+ math "atanh"
+ math "sinc"
+ if !is_c
+ math "atan2",2
+ math "hypot",2
+ math "erf"
+ math "erfc"
+ math "log1p"
+ math "expm1"
+ math "ldexp",2
+ math "frexp",1,"frexp"
+ end
+end
+end
+
+end # other than Bit
diff --git a/ext/numo/narray/gen/tmpl/accum.c b/ext/numo/narray/gen/tmpl/accum.c
new file mode 100644
index 0000000..feb2e54
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/accum.c
@@ -0,0 +1,48 @@
+<% (is_float ? ["","_nan"] : [""]).each do |j| %>
+static void
+<%=c_iter%><%=j%>(na_loop_t *const lp)
+{
+ size_t n;
+ char *p1, *p2;
+ ssize_t s1;
+
+ INIT_COUNTER(lp, n);
+ INIT_PTR(lp, 0, p1, s1);
+ p2 = lp->args[1].ptr + lp->args[1].iter[0].pos;
+
+ *(<%=dtype%>*)p2 = f_<%=name%><%=j%>(n,p1,s1);
+}
+<% end %>
+
+/*
+ <%=name%> of self.
+<% if is_float %>
+ @overload <%=name%>(axis:nil, keepdims:false, nan:false)
+ @param [TrueClass] nan If true, apply NaN-aware algorithm (avoid NaN for sum/mean etc, or, return NaN for min/max etc).
+<% else %>
+ @overload <%=name%>(axis:nil, keepdims:false)
+<% end %>
+ @param [Numeric,Array,Range] axis (keyword) Affected dimensions.
+ @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in the result array as dimensions with size one.
+ @return [Numo::<%=class_name%>] returns result of <%=name%>.
+*/
+static VALUE
+<%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
+{
+ VALUE v, reduce;
+ ndfunc_arg_in_t ain[2] = {{cT,0},{sym_reduce,0}};
+ ndfunc_arg_out_t aout[1] = {{<%=result_class%>,0}};
+ ndfunc_t ndf = { <%=c_iter%>, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE, 2, 1, ain, aout };
+
+ <% if is_float %>
+ reduce = na_reduce_dimension(argc, argv, 1, &self, &ndf, <%=c_iter%>_nan);
+ <% else %>
+ reduce = na_reduce_dimension(argc, argv, 1, &self, &ndf, 0);
+ <% end %>
+ v = na_ndloop(&ndf, 2, self, reduce);
+ <% if result_class == "cT" %>
+ return <%=type_name%>_extract(v);
+ <% else %>
+ return rb_funcall(v,rb_intern("extract"),0);
+ <% end %>
+}
diff --git a/ext/numo/narray/gen/tmpl/accum_binary.c b/ext/numo/narray/gen/tmpl/accum_binary.c
new file mode 100644
index 0000000..ed2579f
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/accum_binary.c
@@ -0,0 +1,96 @@
+<% (is_float ? ["","_nan"] : [""]).each do |j| %>
+static void
+<%=c_iter%><%=j%>(na_loop_t *const lp)
+{
+ size_t i;
+ char *p1, *p2, *p3;
+ ssize_t s1, s2, s3;
+ dtype x, y, z;
+
+ INIT_COUNTER(lp, i);
+ INIT_PTR(lp, 0, p1, s1);
+ INIT_PTR(lp, 1, p2, s2);
+ INIT_PTR(lp, 2, p3, s3);
+ if (s3==0) {
+ // Reduce loop
+ GET_DATA(p3,dtype,z);
+ for (; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ GET_DATA_STRIDE(p2,s2,dtype,y);
+ m_<%=name%><%=j%>(x,y,z);
+ }
+ SET_DATA(p3,dtype,z);
+ } else {
+ for (; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ GET_DATA_STRIDE(p2,s2,dtype,y);
+ GET_DATA(p3,dtype,z);
+ m_<%=name%><%=j%>(x,y,z);
+ SET_DATA_STRIDE(p3,s3,dtype,z);
+ }
+ }
+}
+<% end %>
+
+static VALUE
+<%=c_func%>_self(int argc, VALUE *argv, VALUE self)
+{
+ VALUE v, reduce;
+ VALUE naryv[2];
+ ndfunc_arg_in_t ain[4] = {{cT,0},{cT,0},{sym_reduce,0},{sym_init,0}};
+ ndfunc_arg_out_t aout[1] = {{cT,0}};
+ ndfunc_t ndf = { <%=c_iter%>, STRIDE_LOOP_NIP, 4, 1, ain, aout };
+
+ if (argc < 1) {
+ rb_raise(rb_eArgError,"wrong number of arguments (%d for >=1)",argc);
+ }
+ // should fix below: [self.ndim,other.ndim].max or?
+ naryv[0] = self;
+ naryv[1] = argv[0];
+ <% if is_float %>
+ reduce = na_reduce_dimension(argc-1, argv+1, 2, naryv, &ndf, <%=c_iter%>_nan);
+ <% else %>
+ reduce = na_reduce_dimension(argc-1, argv+1, 2, naryv, &ndf, 0);
+ <% end %>
+
+ v = na_ndloop(&ndf, 4, self, argv[0], reduce, m_<%=name%>_init);
+ return <%=type_name%>_extract(v);
+}
+
+/*
+ Binary <%=name%>.
+
+<% if is_float %>
+ @overload <%=op_map%>(other, axis:nil, keepdims:false, nan:false)
+<% else %>
+ @overload <%=op_map%>(other, axis:nil, keepdims:false)
+<% end %>
+ @param [Numo::NArray,Numeric] other
+ @param [Numeric,Array,Range] axis (keyword) Affected dimensions.
+ @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in the result array as dimensions with size one.
+<% if is_float %>
+ @param [TrueClass] nan (keyword) If true, apply NaN-aware algorithm (avoid NaN if exists).
+<% end %>
+ @return [Numo::NArray] <%=name%> of self and other.
+*/
+static VALUE
+<%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
+{
+ <% if !is_object %>
+ VALUE klass, v;
+ <% end %>
+ if (argc < 1) {
+ rb_raise(rb_eArgError,"wrong number of arguments (%d for >=1)",argc);
+ }
+ <% if is_object %>
+ return <%=c_func%>_self(argc, argv, self);
+ <% else %>
+ klass = na_upcast(CLASS_OF(self),CLASS_OF(argv[0]));
+ if (klass==cT) {
+ return <%=c_func%>_self(argc, argv, self);
+ } else {
+ v = rb_funcall(klass, id_cast, 1, self);
+ return rb_funcall2(v, rb_intern("<%=name%>"), argc, argv);
+ }
+ <% end %>
+}
diff --git a/ext/numo/narray/gen/tmpl/accum_index.c b/ext/numo/narray/gen/tmpl/accum_index.c
new file mode 100644
index 0000000..2514cc7
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/accum_index.c
@@ -0,0 +1,71 @@
+<% (is_float ? ["","_nan"] : [""]).each do |j|
+ [64,32].each do |i| %>
+#define idx_t int<%=i%>_t
+static void
+<%=c_iter%>_index<%=i%><%=j%>(na_loop_t *const lp)
+{
+ size_t n, idx;
+ char *d_ptr, *i_ptr, *o_ptr;
+ ssize_t d_step, i_step;
+
+ INIT_COUNTER(lp, n);
+ INIT_PTR(lp, 0, d_ptr, d_step);
+
+ idx = f_<%=name%><%=j%>(n,d_ptr,d_step);
+
+ INIT_PTR(lp, 1, i_ptr, i_step);
+ o_ptr = NDL_PTR(lp,2);
+ *(idx_t*)o_ptr = *(idx_t*)(i_ptr + i_step * idx);
+}
+#undef idx_t
+<% end;end %>
+
+/*
+ <%=name%>. Return an index of result.
+<% if is_float %>
+ @overload <%=name%>(axis:nil, nan:false)
+ @param [TrueClass] nan If true, apply NaN-aware algorithm (return NaN posision if exist).
+<% else %>
+ @overload <%=name%>(axis:nil)
+<% end %>
+ @param [Numeric,Array,Range] axis Affected dimensions.
+ @return [Integer,Numo::Int] returns result index of <%=name%>.
+ @example
+ Numo::NArray[3,4,1,2].min_index => 3
+ */
+static VALUE
+<%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
+{
+ narray_t *na;
+ VALUE idx, reduce;
+ ndfunc_arg_in_t ain[3] = {{Qnil,0},{Qnil,0},{sym_reduce,0}};
+ ndfunc_arg_out_t aout[1] = {{0,0,0}};
+ ndfunc_t ndf = {0, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT, 3,1, ain,aout};
+
+ GetNArray(self,na);
+ if (na->ndim==0) {
+ return INT2FIX(0);
+ }
+ if (na->size > (~(u_int32_t)0)) {
+ aout[0].type = numo_cInt64;
+ idx = nary_new(numo_cInt64, na->ndim, na->shape);
+ ndf.func = <%=c_iter%>_index64;
+ <% if is_float %>
+ reduce = na_reduce_dimension(argc, argv, 1, &self, &ndf, <%=c_iter%>_index64_nan);
+ <% else %>
+ reduce = na_reduce_dimension(argc, argv, 1, &self, &ndf, 0);
+ <% end %>
+ } else {
+ aout[0].type = numo_cInt32;
+ idx = nary_new(numo_cInt32, na->ndim, na->shape);
+ ndf.func = <%=c_iter%>_index32;
+ <% if is_float %>
+ reduce = na_reduce_dimension(argc, argv, 1, &self, &ndf, <%=c_iter%>_index32_nan);
+ <% else %>
+ reduce = na_reduce_dimension(argc, argv, 1, &self, &ndf, 0);
+ <% end %>
+ }
+ rb_funcall(idx, rb_intern("seq"), 0);
+
+ return na_ndloop(&ndf, 3, self, idx, reduce);
+}
diff --git a/ext/numo/narray/gen/tmpl/alloc_func.c b/ext/numo/narray/gen/tmpl/alloc_func.c
new file mode 100644
index 0000000..e3ddda4
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/alloc_func.c
@@ -0,0 +1,107 @@
+static size_t
+<%=type_name%>_memsize(const void* ptr)
+{
+ size_t size = sizeof(narray_data_t);
+ const narray_data_t *na = (const narray_data_t*)ptr;
+
+ assert(na->base.type == NARRAY_DATA_T);
+
+ if (na->ptr != NULL) {
+ <% if is_bit %>
+ size += ((na->base.size-1)/8/sizeof(BIT_DIGIT)+1)*sizeof(BIT_DIGIT);
+ <% else %>
+ size += na->base.size * sizeof(dtype);
+ <% end %>
+ }
+ if (na->base.size > 0) {
+ if (na->base.shape != NULL && na->base.shape != &(na->base.size)) {
+ size += sizeof(size_t) * na->base.ndim;
+ }
+ }
+ return size;
+}
+
+static void
+<%=type_name%>_free(void* ptr)
+{
+ narray_data_t *na = (narray_data_t*)ptr;
+
+ assert(na->base.type == NARRAY_DATA_T);
+
+ if (na->ptr != NULL) {
+ xfree(na->ptr);
+ na->ptr = NULL;
+ }
+ if (na->base.size > 0) {
+ if (na->base.shape != NULL && na->base.shape != &(na->base.size)) {
+ xfree(na->base.shape);
+ na->base.shape = NULL;
+ }
+ }
+ xfree(na);
+}
+
+static narray_type_info_t <%=type_name%>_info = {
+ <% if is_bit %>
+ 1, // element_bits
+ 0, // element_bytes
+ 1, // element_stride (in bits)
+ <% else %>
+ 0, // element_bits
+ sizeof(dtype), // element_bytes
+ sizeof(dtype), // element_stride (in bytes)
+ <% end %>
+};
+
+<% if is_object %>
+static void
+<%=type_name%>_gc_mark(void *ptr)
+{
+ size_t n, i;
+ VALUE *a;
+ narray_data_t *na = ptr;
+
+ if (na->ptr) {
+ a = (VALUE*)(na->ptr);
+ n = na->base.size;
+ for (i=0; i<n; i++) {
+ rb_gc_mark(a[i]);
+ }
+ }
+}
+
+const rb_data_type_t <%=type_name%>_data_type = {
+ "<%=full_class_name%>",
+ {<%=type_name%>_gc_mark, <%=type_name%>_free, <%=type_name%>_memsize,},
+ &na_data_type,
+ &<%=type_name%>_info,
+ 0, // flags
+};
+
+<% else %>
+
+const rb_data_type_t <%=type_name%>_data_type = {
+ "<%=full_class_name%>",
+ {0, <%=type_name%>_free, <%=type_name%>_memsize,},
+ &na_data_type,
+ &<%=type_name%>_info,
+ 0, // flags
+};
+
+<% end %>
+
+VALUE
+<%=c_func(0)%>(VALUE klass)
+{
+ narray_data_t *na = ALLOC(narray_data_t);
+
+ na->base.ndim = 0;
+ na->base.type = NARRAY_DATA_T;
+ na->base.flag[0] = NA_FL0_INIT;
+ na->base.flag[1] = NA_FL1_INIT;
+ na->base.size = 0;
+ na->base.shape = NULL;
+ na->base.reduce = INT2FIX(0);
+ na->ptr = NULL;
+ return TypedData_Wrap_Struct(klass, &<%=type_name%>_data_type, (void*)na);
+}
diff --git a/ext/numo/narray/gen/tmpl/allocate.c b/ext/numo/narray/gen/tmpl/allocate.c
new file mode 100644
index 0000000..7dc13a0
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/allocate.c
@@ -0,0 +1,35 @@
+static VALUE
+<%=c_func(0)%>(VALUE self)
+{
+ narray_t *na;
+ char *ptr;
+
+ GetNArray(self,na);
+
+ switch(NA_TYPE(na)) {
+ case NARRAY_DATA_T:
+ ptr = NA_DATA_PTR(na);
+ if (na->size > 0 && ptr == NULL) {
+ ptr = xmalloc(sizeof(dtype) * na->size);
+ <% if is_object %>
+ { size_t i;
+ VALUE *a = (VALUE*)ptr;
+ for (i=na->size; i--;) {
+ *a++ = Qnil;
+ }
+ }
+ <% end %>
+ NA_DATA_PTR(na) = ptr;
+ }
+ break;
+ case NARRAY_VIEW_T:
+ rb_funcall(NA_VIEW_DATA(na), rb_intern("allocate"), 0);
+ break;
+ case NARRAY_FILEMAP_T:
+ //ptr = ((narray_filemap_t*)na)->ptr;
+ // to be implemented
+ default:
+ rb_bug("invalid narray type : %d",NA_TYPE(na));
+ }
+ return self;
+}
diff --git a/ext/numo/narray/gen/tmpl/aref.c b/ext/numo/narray/gen/tmpl/aref.c
new file mode 100644
index 0000000..a1b4c02
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/aref.c
@@ -0,0 +1,53 @@
+/*
+ Array element referenece or slice view.
+ @overload [](dim0,...,dimL)
+ @param [Numeric,Range,etc] dim0,...,dimL Multi-dimensional Index.
+ @return [Numeric,NArray::<%=class_name%>] Element object or NArray view.
+
+ --- Returns the element at +dim0+, +dim1+, ... are Numeric indices
+ for each dimension, or returns a NArray View as a sliced subarray if
+ +dim0+, +dim1+, ... includes other than Numeric index, e.g., Range
+ or Array or true.
+
+ @example
+ a = Numo::DFloat.new(4,5).seq
+ => Numo::DFloat#shape=[4,5]
+ [[0, 1, 2, 3, 4],
+ [5, 6, 7, 8, 9],
+ [10, 11, 12, 13, 14],
+ [15, 16, 17, 18, 19]]
+
+ a[1,1]
+ => 6.0
+
+ a[1..3,1]
+ => Numo::DFloat#shape=[3]
+ [6, 11, 16]
+
+ a[1,[1,3,4]]
+ => Numo::DFloat#shape=[3]
+ [6, 8, 9]
+
+ a[true,2].fill(99)
+ a
+ => Numo::DFloat#shape=[4,5]
+ [[0, 1, 99, 3, 4],
+ [5, 6, 99, 8, 9],
+ [10, 11, 99, 13, 14],
+ [15, 16, 99, 18, 19]]
+ */
+static VALUE
+<%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
+{
+ int nd;
+ size_t pos;
+ char *ptr;
+
+ nd = na_get_result_dimension(self, argc, argv, sizeof(dtype), &pos);
+ if (nd) {
+ return na_aref_main(argc, argv, self, 0, nd);
+ } else {
+ ptr = na_get_pointer_for_read(self) + pos;
+ return m_extract(ptr);
+ }
+}
diff --git a/ext/numo/narray/gen/tmpl/aset.c b/ext/numo/narray/gen/tmpl/aset.c
new file mode 100644
index 0000000..8e206c6
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/aset.c
@@ -0,0 +1,65 @@
+/*
+ Array element(s) set.
+ @overload []=(dim0,..,dimL,val)
+ @param [Numeric,Range,etc] dim0,..,dimL Multi-dimensional Index.
+ @param [Numeric,Numo::NArray,etc] val Value(s) to be set to self.
+ @return [Numeric] returns val (last argument).
+
+ --- Replace element(s) at +dim0+, +dim1+, ... (index/range/array/true
+ for each dimention). Broadcasting mechanism is applied.
+
+ @example
+ a = Numo::DFloat.new(3,4).seq
+ => Numo::DFloat#shape=[3,4]
+ [[0, 1, 2, 3],
+ [4, 5, 6, 7],
+ [8, 9, 10, 11]]
+
+ a[1,2]=99
+ a
+ => Numo::DFloat#shape=[3,4]
+ [[0, 1, 2, 3],
+ [4, 5, 99, 7],
+ [8, 9, 10, 11]]
+
+ a[1,[0,2]] = [101,102]
+ a
+ => Numo::DFloat#shape=[3,4]
+ [[0, 1, 2, 3],
+ [101, 5, 102, 7],
+ [8, 9, 10, 11]]
+
+ a[1,true]=99
+ a
+ => Numo::DFloat#shape=[3,4]
+ [[0, 1, 2, 3],
+ [99, 99, 99, 99],
+ [8, 9, 10, 11]]
+
+*/
+static VALUE
+<%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
+{
+ int nd;
+ size_t pos;
+ char *ptr;
+ VALUE a;
+ dtype x;
+
+ argc--;
+ if (argc==0) {
+ <%=c_func.sub(/_aset/,"_store")%>(self, argv[argc]);
+ } else {
+ nd = na_get_result_dimension(self, argc, argv, sizeof(dtype), &pos);
+ if (nd) {
+ a = na_aref_main(argc, argv, self, 0, nd);
+ <%=c_func.sub(/_aset/,"_store")%>(a, argv[argc]);
+ } else {
+ x = <%=type_name%>_extract_data(argv[argc]);
+ ptr = na_get_pointer_for_read_write(self) + pos;
+ *(dtype*)ptr = x;
+ }
+
+ }
+ return argv[argc];
+}
diff --git a/ext/numo/narray/gen/tmpl/binary.c b/ext/numo/narray/gen/tmpl/binary.c
new file mode 100644
index 0000000..135f7b4
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/binary.c
@@ -0,0 +1,57 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i, n;
+ char *p1, *p2, *p3;
+ ssize_t s1, s2, s3;
+ dtype x, y;
+ INIT_COUNTER(lp, n);
+ INIT_PTR(lp, 0, p1, s1);
+ INIT_PTR(lp, 1, p2, s2);
+ INIT_PTR(lp, 2, p3, s3);
+ for (i=n; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ GET_DATA_STRIDE(p2,s2,dtype,y);
+<% if is_int and %w[div mod divmod].include? name %>
+ if (y==0) {
+ lp->err_type = rb_eZeroDivError;
+ return;
+ }
+<% end %>
+ x = m_<%=name%>(x,y);
+ SET_DATA_STRIDE(p3,s3,dtype,x);
+ }
+}
+
+static VALUE
+<%=c_func%>_self(VALUE self, VALUE other)
+{
+ ndfunc_arg_in_t ain[2] = {{cT,0},{cT,0}};
+ ndfunc_arg_out_t aout[1] = {{cT,0}};
+ ndfunc_t ndf = { <%=c_iter%>, STRIDE_LOOP, 2, 1, ain, aout };
+
+ return na_ndloop(&ndf, 2, self, other);
+}
+
+/*
+ Binary <%=name%>.
+ @overload <%=op_map%> other
+ @param [Numo::NArray,Numeric] other
+ @return [Numo::NArray] self <%=op_map%> other
+*/
+static VALUE
+<%=c_func(1)%>(VALUE self, VALUE other)
+{
+ <% if is_object %>
+ return <%=c_func%>_self(self, other);
+ <% else %>
+ VALUE klass, v;
+ klass = na_upcast(CLASS_OF(self),CLASS_OF(other));
+ if (klass==cT) {
+ return <%=c_func%>_self(self, other);
+ } else {
+ v = rb_funcall(klass, id_cast, 1, self);
+ return rb_funcall(v, <%=id_op%>, 1, other);
+ }
+ <% end %>
+}
diff --git a/ext/numo/narray/gen/tmpl/binary2.c b/ext/numo/narray/gen/tmpl/binary2.c
new file mode 100644
index 0000000..e844afd
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/binary2.c
@@ -0,0 +1,59 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i, n;
+ char *p1, *p2, *p3, *p4;
+ ssize_t s1, s2, s3, s4;
+ dtype x, y, a, b;
+ INIT_COUNTER(lp, n);
+ INIT_PTR(lp, 0, p1, s1);
+ INIT_PTR(lp, 1, p2, s2);
+ INIT_PTR(lp, 2, p3, s3);
+ INIT_PTR(lp, 3, p4, s4);
+ for (i=n; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ GET_DATA_STRIDE(p2,s2,dtype,y);
+<% if is_int and %w[divmod].include? name %>
+ if (y==0) {
+ lp->err_type = rb_eZeroDivError;
+ return;
+ }
+<% end %>
+ m_<%=name%>(x,y,a,b);
+ SET_DATA_STRIDE(p3,s3,dtype,a);
+ SET_DATA_STRIDE(p4,s4,dtype,b);
+ }
+}
+
+static VALUE
+<%=c_func%>_self(VALUE self, VALUE other)
+{
+ ndfunc_arg_in_t ain[2] = {{cT,0},{cT,0}};
+ ndfunc_arg_out_t aout[2] = {{cT,0},{cT,0}};
+ ndfunc_t ndf = { <%=c_iter%>, STRIDE_LOOP, 2, 2, ain, aout };
+
+ return na_ndloop(&ndf, 2, self, other);
+}
+
+/*
+ Binary <%=name%>.
+ @overload <%=op_map%> other
+ @param [Numo::NArray,Numeric] other
+ @return [Numo::NArray] <%=name%> of self and other.
+*/
+static VALUE
+<%=c_func(1)%>(VALUE self, VALUE other)
+{
+ <% if is_object %>
+ return <%=c_func%>_self(self, other);
+ <% else %>
+ VALUE klass, v;
+ klass = na_upcast(CLASS_OF(self),CLASS_OF(other));
+ if (klass==cT) {
+ return <%=c_func%>_self(self, other);
+ } else {
+ v = rb_funcall(klass, id_cast, 1, self);
+ return rb_funcall(v, <%=id_op%>, 1, other);
+ }
+ <% end %>
+}
diff --git a/ext/numo/narray/gen/tmpl/binary_s.c b/ext/numo/narray/gen/tmpl/binary_s.c
new file mode 100644
index 0000000..347ee8d
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/binary_s.c
@@ -0,0 +1,34 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ char *p1, *p2, *p3;
+ ssize_t s1, s2, s3;
+ dtype x, y;
+ INIT_COUNTER(lp, i);
+ INIT_PTR(lp, 0, p1, s1);
+ INIT_PTR(lp, 1, p2, s2);
+ INIT_PTR(lp, 2, p3, s3);
+ for (; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ GET_DATA_STRIDE(p2,s2,dtype,y);
+ x = m_<%=name%>(x,y);
+ SET_DATA_STRIDE(p3,s3,dtype,x);
+ }
+}
+
+/*
+ Calculate <%=name%>(a1,a2).
+ @overload <%=name%>(a1,a2)
+ @param [Numo::NArray,Numeric] a1 first value
+ @param [Numo::NArray,Numeric] a2 second value
+ @return [Numo::<%=class_name%>] <%=name%>(a1,a2).
+*/
+static VALUE
+<%=c_func(2)%>(VALUE mod, VALUE a1, VALUE a2)
+{
+ ndfunc_arg_in_t ain[2] = {{cT,0},{cT,0}};
+ ndfunc_arg_out_t aout[1] = {{cT,0}};
+ ndfunc_t ndf = { <%=c_iter%>, STRIDE_LOOP, 2, 1, ain, aout };
+ return na_ndloop(&ndf, 2, a1, a2);
+}
diff --git a/ext/numo/narray/gen/tmpl/bincount.c b/ext/numo/narray/gen/tmpl/bincount.c
new file mode 100644
index 0000000..9cbf164
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/bincount.c
@@ -0,0 +1,180 @@
+// ------- Integer count without weights -------
+<%
+[32,64].each do |bits|
+ cnt_cT = "numo_cUInt#{bits}"
+ cnt_type = "u_int#{bits}_t"
+%>
+static void
+<%=c_iter%>_<%=bits%>(na_loop_t *const lp)
+{
+ size_t i, x, n;
+ char *p1, *p2;
+ ssize_t s1, s2;
+ size_t *idx1;
+
+ INIT_PTR_IDX(lp, 0, p1, s1, idx1);
+ INIT_PTR(lp, 1, p2, s2);
+ i = lp->args[0].shape[0];
+ n = lp->args[1].shape[0];
+
+ // initialize
+ for (x=0; x < n; x++) {
+ *(<%=cnt_type%>*)(p2 + s2*x) = 0;
+ }
+
+ if (idx1) {
+ for (; i--;) {
+ GET_DATA_INDEX(p1,idx1,dtype,x);
+ (*(<%=cnt_type%>*)(p2 + s2*x))++;
+ }
+ } else {
+ for (; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ (*(<%=cnt_type%>*)(p2 + s2*x))++;
+ }
+ }
+}
+
+static VALUE
+<%=c_func%>_<%=bits%>(VALUE self, size_t length)
+{
+ size_t shape_out[1] = {length};
+ ndfunc_arg_in_t ain[1] = {{cT,1}};
+ ndfunc_arg_out_t aout[1] = {{<%=cnt_cT%>,1,shape_out}};
+ ndfunc_t ndf = {<%=c_iter%>_<%=bits%>, NO_LOOP|NDF_STRIDE_LOOP|NDF_INDEX_LOOP,
+ 1, 1, ain, aout};
+
+ return na_ndloop(&ndf, 1, self);
+}
+<% end %>
+// ------- end of Integer count without weights -------
+
+// ------- Float count with weights -------
+<%
+[["SF","float"],
+ ["DF","double"]].each do |fn,cnt_type|
+ cnt_cT = "numo_c#{fn}loat"
+ fn = fn.downcase
+%>
+static void
+<%=c_iter%>_<%=fn%>(na_loop_t *const lp)
+{
+ <%=cnt_type%> w;
+ size_t i, x, n, m;
+ char *p1, *p2, *p3;
+ ssize_t s1, s2, s3;
+
+ INIT_PTR(lp, 0, p1, s1);
+ INIT_PTR(lp, 1, p2, s2);
+ INIT_PTR(lp, 2, p3, s3);
+ i = lp->args[0].shape[0];
+ m = lp->args[1].shape[0];
+ n = lp->args[2].shape[0];
+
+ if (i != m) {
+ rb_raise(nary_eShapeError,
+ "size mismatch along last axis between self and weight");
+ }
+
+ // initialize
+ for (x=0; x < n; x++) {
+ *(<%=cnt_type%>*)(p3 + s3*x) = 0;
+ }
+ for (; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ GET_DATA_STRIDE(p2,s2,<%=cnt_type%>,w);
+ (*(<%=cnt_type%>*)(p3 + s3*x)) += w;
+ }
+}
+
+static VALUE
+<%=c_func%>_<%=fn%>(VALUE self, VALUE weight, size_t length)
+{
+ size_t shape_out[1] = {length};
+ ndfunc_arg_in_t ain[2] = {{cT,1},{<%=cnt_cT%>,1}};
+ ndfunc_arg_out_t aout[1] = {{<%=cnt_cT%>,1,shape_out}};
+ ndfunc_t ndf = {<%=c_iter%>_<%=fn%>, NO_LOOP|NDF_STRIDE_LOOP,
+ 2, 1, ain, aout};
+
+ return na_ndloop(&ndf, 2, self, weight);
+}
+<% end %>
+// ------- end of Float count with weights -------
+
+/*
+ Count the number of occurrences of each non-negative integer value.
+ Only Integer-types has this method.
+
+ @overload <%=name%>([weight], minlength:nil)
+ @param [SFloat or DFloat or Array] weight (optional) Array of
+ float values. Its size along last axis should be same as that of self.
+ @param [Integer] minlength (keyword, optional) Minimum size along
+ last axis for the output array.
+ @return [UInt32 or UInt64 or SFloat or DFloat]
+ Returns Float NArray if weight array is supplied,
+ otherwise returns UInt32 or UInt64 depending on the size along last axis.
+ @example
+ Numo::Int32[0..4].bincount
+ => Numo::UInt32#shape=[5]
+ [1, 1, 1, 1, 1]
+
+ Numo::Int32[0, 1, 1, 3, 2, 1, 7].bincount
+ => Numo::UInt32#shape=[8]
+ [1, 3, 1, 1, 0, 0, 0, 1]
+
+ x = Numo::Int32[0, 1, 1, 3, 2, 1, 7, 23]
+ x.bincount.size == x.max+1
+ => true
+
+ w = Numo::DFloat[0.3, 0.5, 0.2, 0.7, 1.0, -0.6]
+ x = Numo::Int32[0, 1, 1, 2, 2, 2]
+ x.bincount(w)
+ => Numo::DFloat#shape=[3]
+ [0.3, 0.7, 1.1]
+
+*/
+static VALUE
+<%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
+{
+ VALUE weight=Qnil, kw=Qnil;
+ VALUE opts[1] = {Qundef};
+ VALUE v, wclass;
+ ID table[1] = {id_minlength};
+ size_t length, minlength;
+
+ rb_scan_args(argc, argv, "01:", &weight, &kw);
+ rb_get_kwargs(kw, table, 0, 1, opts);
+
+ <% if is_unsigned %>
+ v = <%=type_name%>_max(0,0,self);
+ <% else %>
+ v = <%=type_name%>_minmax(0,0,self);
+ if (m_num_to_data(RARRAY_AREF(v,0)) < 0) {
+ rb_raise(rb_eArgError,"array items must be non-netagive");
+ }
+ v = RARRAY_AREF(v,1);
+ <% end %>
+ length = NUM2SIZET(v) + 1;
+
+ if (opts[0] != Qundef) {
+ minlength = NUM2SIZET(opts[0]);
+ if (minlength > length) {
+ length = minlength;
+ }
+ }
+
+ if (NIL_P(weight)) {
+ if (length > 4294967295ul) {
+ return <%=c_func%>_64(self, length);
+ } else {
+ return <%=c_func%>_32(self, length);
+ }
+ } else {
+ wclass = CLASS_OF(weight);
+ if (wclass == numo_cSFloat) {
+ return <%=c_func%>_sf(self, weight, length);
+ } else {
+ return <%=c_func%>_df(self, weight, length);
+ }
+ }
+}
diff --git a/ext/numo/narray/gen/tmpl/cast.c b/ext/numo/narray/gen/tmpl/cast.c
new file mode 100644
index 0000000..4e2c7c8
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/cast.c
@@ -0,0 +1,44 @@
+<% children.each do |c|%>
+<%= c.result %>
+
+<% end %>
+/*
+ Cast object to Numo::<%=class_name%>.
+ @overload [](elements)
+ @overload <%=name%>(array)
+ @param [Numeric,Array] elements
+ @param [Array] array
+ @return [Numo::<%=class_name%>]
+*/
+static VALUE
+<%=c_func(1)%>(VALUE type, VALUE obj)
+{
+ VALUE v;
+ narray_t *na;
+ dtype x;
+
+ if (CLASS_OF(obj)==cT) {
+ return obj;
+ }
+ if (RTEST(rb_obj_is_kind_of(obj,rb_cNumeric))) {
+ x = m_num_to_data(obj);
+ return <%=type_name%>_new_dim0(x);
+ }
+ if (RTEST(rb_obj_is_kind_of(obj,rb_cArray))) {
+ return <%=find_tmpl("cast_array").c_func%>(obj);
+ }
+ if (IsNArray(obj)) {
+ GetNArray(obj,na);
+ v = nary_new(cT, NA_NDIM(na), NA_SHAPE(na));
+ if (NA_SIZE(na) > 0) {
+ <%=find_tmpl("store").c_func%>(v,obj);
+ }
+ return v;
+ }
+ <% if is_object %>
+ return robject_new_dim0(obj);
+ <% else %>
+ rb_raise(nary_eCastError,"cannot cast to %s",rb_class2name(type));
+ return Qnil;
+ <% end %>
+}
diff --git a/ext/numo/narray/gen/tmpl/cast_array.c b/ext/numo/narray/gen/tmpl/cast_array.c
new file mode 100644
index 0000000..4c22030
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/cast_array.c
@@ -0,0 +1,13 @@
+static VALUE
+<%=c_func(:nodef)%>(VALUE rary)
+{
+ VALUE nary;
+ narray_t *na;
+
+ nary = na_s_new_like(cT, rary);
+ GetNArray(nary,na);
+ if (na->size > 0) {
+ <%=find_tmpl("store").find("array").c_func%>(nary,rary);
+ }
+ return nary;
+}
diff --git a/ext/numo/narray/gen/tmpl/class.c b/ext/numo/narray/gen/tmpl/class.c
new file mode 100644
index 0000000..ab1b75b
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/class.c
@@ -0,0 +1,9 @@
+/*
+ class definition: <%= full_class_name %>
+*/
+
+VALUE <%=class_var%>;
+
+static VALUE <%= find('store').c_func %>(VALUE,VALUE);
+
+<%= method_code %>
diff --git a/ext/numo/narray/gen/tmpl/clip.c b/ext/numo/narray/gen/tmpl/clip.c
new file mode 100644
index 0000000..17e18db
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/clip.c
@@ -0,0 +1,118 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ char *p1, *p2, *p3, *p4;
+ ssize_t s1, s2, s3, s4;
+ dtype x, min, max;
+ INIT_COUNTER(lp, i);
+ INIT_PTR(lp, 0, p1, s1);
+ INIT_PTR(lp, 1, p2, s2);
+ INIT_PTR(lp, 2, p3, s3);
+ INIT_PTR(lp, 3, p4, s4);
+ for (; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ GET_DATA_STRIDE(p2,s2,dtype,min);
+ GET_DATA_STRIDE(p3,s3,dtype,max);
+ if (m_gt(min,max)) {rb_raise(nary_eOperationError,"min is greater than max");}
+ if (m_lt(x,min)) {x=min;}
+ if (m_gt(x,max)) {x=max;}
+ SET_DATA_STRIDE(p4,s4,dtype,x);
+ }
+}
+
+static void
+<%=c_iter%>_min(na_loop_t *const lp)
+{
+ size_t i;
+ char *p1, *p2, *p3;
+ ssize_t s1, s2, s3;
+ dtype x, min;
+ INIT_COUNTER(lp, i);
+ INIT_PTR(lp, 0, p1, s1);
+ INIT_PTR(lp, 1, p2, s2);
+ INIT_PTR(lp, 2, p3, s3);
+ for (; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ GET_DATA_STRIDE(p2,s2,dtype,min);
+ if (m_lt(x,min)) {x=min;}
+ SET_DATA_STRIDE(p3,s3,dtype,x);
+ }
+}
+
+static void
+<%=c_iter%>_max(na_loop_t *const lp)
+{
+ size_t i;
+ char *p1, *p2, *p3;
+ ssize_t s1, s2, s3;
+ dtype x, max;
+ INIT_COUNTER(lp, i);
+ INIT_PTR(lp, 0, p1, s1);
+ INIT_PTR(lp, 1, p2, s2);
+ INIT_PTR(lp, 2, p3, s3);
+ for (; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ GET_DATA_STRIDE(p2,s2,dtype,max);
+ if (m_gt(x,max)) {x=max;}
+ SET_DATA_STRIDE(p3,s3,dtype,x);
+ }
+}
+
+/*
+ Clip array elements by [min,max].
+ If either of min or max is nil, one side is clipped.
+ @overload <%=name%>(min,max)
+ @param [Numo::NArray,Numeric] min
+ @param [Numo::NArray,Numeric] max
+ @return [Numo::NArray] result of clip.
+
+ @example
+ a = Numo::Int32.new(10).seq
+ p a.clip(1,8)
+ # Numo::Int32#shape=[10]
+ # [1, 1, 2, 3, 4, 5, 6, 7, 8, 8]
+
+ p a
+ # Numo::Int32#shape=[10]
+ # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+
+ p a.inplace.clip(3,6)
+ # Numo::Int32(view)#shape=[10]
+ # [3, 3, 3, 3, 4, 5, 6, 6, 6, 6]
+
+ p a
+ # Numo::Int32#shape=[10]
+ # [3, 3, 3, 3, 4, 5, 6, 6, 6, 6]
+
+ p a = Numo::Int32.new(10).seq
+ # Numo::Int32#shape=[10]
+ # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+
+ p a.clip([3,4,1,1,1,4,4,4,4,4], 8)
+ # Numo::Int32#shape=[10]
+ # [3, 4, 2, 3, 4, 5, 6, 7, 8, 8]
+*/
+static VALUE
+<%=c_func(2)%>(VALUE self, VALUE min, VALUE max)
+{
+ ndfunc_arg_in_t ain[3] = {{Qnil,0},{cT,0},{cT,0}};
+ ndfunc_arg_out_t aout[1] = {{cT,0}};
+ ndfunc_t ndf_min = { <%=c_iter%>_min, STRIDE_LOOP, 2, 1, ain, aout };
+ ndfunc_t ndf_max = { <%=c_iter%>_max, STRIDE_LOOP, 2, 1, ain, aout };
+ ndfunc_t ndf_both = { <%=c_iter%>, STRIDE_LOOP, 3, 1, ain, aout };
+
+ if (RTEST(min)) {
+ if (RTEST(max)) {
+ return na_ndloop(&ndf_both, 3, self, min, max);
+ } else {
+ return na_ndloop(&ndf_min, 2, self, min);
+ }
+ } else {
+ if (RTEST(max)) {
+ return na_ndloop(&ndf_max, 2, self, max);
+ }
+ }
+ rb_raise(rb_eArgError,"min and max are not given");
+ return Qnil;
+}
diff --git a/ext/numo/narray/gen/tmpl/coerce_cast.c b/ext/numo/narray/gen/tmpl/coerce_cast.c
new file mode 100644
index 0000000..e799bad
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/coerce_cast.c
@@ -0,0 +1,10 @@
+/*
+ return NArray with cast to the type of self.
+ @overload coerce_cast(type)
+ @return [nil]
+*/
+static VALUE
+<%=c_func(1)%>(VALUE self, VALUE type)
+{
+ return Qnil;
+}
diff --git a/ext/numo/narray/gen/tmpl/cond_binary.c b/ext/numo/narray/gen/tmpl/cond_binary.c
new file mode 100644
index 0000000..8bee4e4
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/cond_binary.c
@@ -0,0 +1,55 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ char *p1, *p2;
+ BIT_DIGIT *a3;
+ size_t p3;
+ ssize_t s1, s2, s3;
+ dtype x, y;
+ BIT_DIGIT b;
+ INIT_COUNTER(lp, i);
+ INIT_PTR(lp, 0, p1, s1);
+ INIT_PTR(lp, 1, p2, s2);
+ INIT_PTR_BIT(lp, 2, a3, p3, s3);
+ for (; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ GET_DATA_STRIDE(p2,s2,dtype,y);
+ b = (m_<%=name%>(x,y)) ? 1:0;
+ STORE_BIT(a3,p3,b);
+ p3+=s3;
+ }
+}
+
+static VALUE
+<%=c_func%>_self(VALUE self, VALUE other)
+{
+ ndfunc_arg_in_t ain[2] = {{cT,0},{cT,0}};
+ ndfunc_arg_out_t aout[1] = {{numo_cBit,0}};
+ ndfunc_t ndf = { <%=c_iter%>, STRIDE_LOOP, 2, 1, ain, aout };
+
+ return na_ndloop(&ndf, 2, self, other);
+}
+
+/*
+ Comparison <%=name%> other.
+ @overload <%=op_map%> other
+ @param [Numo::NArray,Numeric] other
+ @return [Numo::Bit] result of self <%=name%> other.
+*/
+static VALUE
+<%=c_func(1)%>(VALUE self, VALUE other)
+{
+ <% if is_object %>
+ return <%=c_func%>_self(self, other);
+ <% else %>
+ VALUE klass, v;
+ klass = na_upcast(CLASS_OF(self),CLASS_OF(other));
+ if (klass==cT) {
+ return <%=c_func%>_self(self, other);
+ } else {
+ v = rb_funcall(klass, id_cast, 1, self);
+ return rb_funcall(v, <%=id_op%>, 1, other);
+ }
+ <% end %>
+}
diff --git a/ext/numo/narray/gen/tmpl/cond_unary.c b/ext/numo/narray/gen/tmpl/cond_unary.c
new file mode 100644
index 0000000..2d7a07a
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/cond_unary.c
@@ -0,0 +1,45 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ char *p1;
+ BIT_DIGIT *a2;
+ size_t p2;
+ ssize_t s1, s2;
+ size_t *idx1;
+ dtype x;
+ BIT_DIGIT b;
+ INIT_COUNTER(lp, i);
+ INIT_PTR_IDX(lp, 0, p1, s1, idx1);
+ INIT_PTR_BIT(lp, 1, a2, p2, s2);
+ if (idx1) {
+ for (; i--;) {
+ GET_DATA_INDEX(p1,idx1,dtype,x);
+ b = (m_<%=name%>(x)) ? 1:0;
+ STORE_BIT(a2,p2,b);
+ p2+=s2;
+ }
+ } else {
+ for (; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ b = (m_<%=name%>(x)) ? 1:0;
+ STORE_BIT(a2,p2,b);
+ p2+=s2;
+ }
+ }
+}
+
+/*
+ Condition of <%=name%>.
+ @overload <%=name%>
+ @return [Numo::Bit] Condition of <%=name%>.
+*/
+static VALUE
+<%=c_func(0)%>(VALUE self)
+{
+ ndfunc_arg_in_t ain[1] = {{cT,0}};
+ ndfunc_arg_out_t aout[1] = {{numo_cBit,0}};
+ ndfunc_t ndf = { <%=c_iter%>, FULL_LOOP, 1, 1, ain, aout };
+
+ return na_ndloop(&ndf, 1, self);
+}
diff --git a/ext/numo/narray/gen/tmpl/cum.c b/ext/numo/narray/gen/tmpl/cum.c
new file mode 100644
index 0000000..6f589f8
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/cum.c
@@ -0,0 +1,49 @@
+<% (is_float ? ["","_nan"] : [""]).each do |j| %>
+static void
+<%=c_iter%><%=j%>(na_loop_t *const lp)
+{
+ size_t i;
+ char *p1, *p2;
+ ssize_t s1, s2;
+ dtype x, y;
+
+ INIT_COUNTER(lp, i);
+ INIT_PTR(lp, 0, p1, s1);
+ INIT_PTR(lp, 1, p2, s2);
+ //printf("i=%lu p1=%lx s1=%lu p2=%lx s2=%lu\n",i,(size_t)p1,s1,(size_t)p2,s2);
+
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ SET_DATA_STRIDE(p2,s2,dtype,x);
+ //printf("i=%lu x=%f\n",i,x);
+ for (i--; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,y);
+ m_<%=name%><%=j%>(x,y);
+ SET_DATA_STRIDE(p2,s2,dtype,x);
+ //printf("i=%lu x=%f\n",i,x);
+ }
+}
+<% end %>
+
+/*
+ <%=name%> of self.
+ @overload <%=name%>(axis:nil, nan:false)
+ @param [Numeric,Array,Range] axis Affected dimensions.
+ @param [TrueClass] nan If true, apply NaN-aware algorithm (avoid NaN if exists).
+ @return [Numo::<%=class_name%>] <%=name%> of self.
+*/
+static VALUE
+<%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
+{
+ VALUE reduce;
+ ndfunc_arg_in_t ain[2] = {{cT,0},{sym_reduce,0}};
+ ndfunc_arg_out_t aout[1] = {{cT,0}};
+ ndfunc_t ndf = { <%=c_iter%>, STRIDE_LOOP|NDF_FLAT_REDUCE|NDF_CUM,
+ 2, 1, ain, aout };
+
+ <% if is_float %>
+ reduce = na_reduce_dimension(argc, argv, 1, &self, &ndf, <%=c_iter%>_nan);
+ <% else %>
+ reduce = na_reduce_dimension(argc, argv, 1, &self, &ndf, 0);
+ <% end %>
+ return na_ndloop(&ndf, 2, self, reduce);
+}
diff --git a/ext/numo/narray/gen/tmpl/each.c b/ext/numo/narray/gen/tmpl/each.c
new file mode 100644
index 0000000..11a4c24
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/each.c
@@ -0,0 +1,43 @@
+void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i, s1;
+ char *p1;
+ size_t *idx1;
+ dtype x;
+ VALUE y;
+
+ INIT_COUNTER(lp, i);
+ INIT_PTR_IDX(lp, 0, p1, s1, idx1);
+ if (idx1) {
+ for (; i--;) {
+ GET_DATA_INDEX(p1,idx1,dtype,x);
+ y = m_data_to_num(x);
+ rb_yield(y);
+ }
+ } else {
+ for (; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ y = m_data_to_num(x);
+ rb_yield(y);
+ }
+ }
+}
+
+/*
+ Calls the given block once for each element in self,
+ passing that element as a parameter.
+ @overload <%=name%>
+ @return [Numo::NArray] self
+ For a block {|x| ... }
+ @yield [x] x is element of NArray.
+*/
+static VALUE
+<%=c_func(0)%>(VALUE self)
+{
+ ndfunc_arg_in_t ain[1] = {{Qnil,0}};
+ ndfunc_t ndf = {<%=c_iter%>, FULL_LOOP_NIP, 1,0, ain,0};
+
+ na_ndloop(&ndf, 1, self);
+ return self;
+}
diff --git a/ext/numo/narray/gen/tmpl/each_with_index.c b/ext/numo/narray/gen/tmpl/each_with_index.c
new file mode 100644
index 0000000..49fc9e5
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/each_with_index.c
@@ -0,0 +1,64 @@
+static inline void
+yield_each_with_index(dtype x, size_t *c, VALUE *a, int nd, int md)
+{
+ int j;
+
+ a[0] = m_data_to_num(x);
+ for (j=0; j<=nd; j++) {
+ a[j+1] = SIZET2NUM(c[j]);
+ }
+ rb_yield(rb_ary_new4(md,a));
+}
+
+
+void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i, s1;
+ char *p1;
+ size_t *idx1;
+ dtype x;
+ VALUE *a;
+ size_t *c;
+ int nd, md;
+
+ c = (size_t*)(lp->opt_ptr);
+ nd = lp->ndim - 1;
+ md = lp->ndim + 1;
+ a = ALLOCA_N(VALUE,md);
+
+ INIT_COUNTER(lp, i);
+ INIT_PTR_IDX(lp, 0, p1, s1, idx1);
+ c[nd] = 0;
+ if (idx1) {
+ for (; i--;) {
+ GET_DATA_INDEX(p1,idx1,dtype,x);
+ yield_each_with_index(x,c,a,nd,md);
+ c[nd]++;
+ }
+ } else {
+ for (; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ yield_each_with_index(x,c,a,nd,md);
+ c[nd]++;
+ }
+ }
+}
+
+/*
+ Invokes the given block once for each element of self,
+ passing that element and indices along each axis as parameters.
+ @overload <%=name%>
+ @return [Numo::NArray] self
+ For a block {|x,i,j,...| ... }
+ @yield [x,i,j,...] x is an element, i,j,... are multidimensional indices.
+*/
+static VALUE
+<%=c_func(0)%>(VALUE self)
+{
+ ndfunc_arg_in_t ain[1] = {{Qnil,0}};
+ ndfunc_t ndf = {<%=c_iter%>, FULL_LOOP_NIP, 1,0, ain,0};
+
+ na_ndloop_with_index(&ndf, 1, self);
+ return self;
+}
diff --git a/ext/numo/narray/gen/tmpl/extract.c b/ext/numo/narray/gen/tmpl/extract.c
new file mode 100644
index 0000000..7fe8944
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/extract.c
@@ -0,0 +1,23 @@
+/*
+ Extract an element only if self is a dimensionless NArray.
+ @overload extract
+ @return [Numeric,Numo::NArray]
+ --- Extract element value as Ruby Object if self is a dimensionless NArray,
+ otherwise returns self.
+*/
+static VALUE
+<%=c_func(0)%>(VALUE self)
+{
+ volatile VALUE v;
+ char *ptr;
+ narray_t *na;
+ GetNArray(self,na);
+
+ if (na->ndim==0) {
+ ptr = na_get_pointer_for_read(self) + na_get_offset(self);
+ v = m_extract(ptr);
+ na_release_lock(self);
+ return v;
+ }
+ return self;
+}
diff --git a/ext/numo/narray/gen/tmpl/extract_data.c b/ext/numo/narray/gen/tmpl/extract_data.c
new file mode 100644
index 0000000..b64a39c
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/extract_data.c
@@ -0,0 +1,48 @@
+/*
+ Convert a data value of obj (with a single element) to dtype.
+*/
+static dtype
+<%=c_func(:nodef)%>(VALUE obj)
+{
+ narray_t *na;
+ dtype x;
+ char *ptr;
+ size_t pos;
+ VALUE r, klass;
+
+ if (IsNArray(obj)) {
+ GetNArray(obj,na);
+ if (na->size != 1) {
+ rb_raise(nary_eShapeError,"narray size should be 1");
+ }
+ klass = CLASS_OF(obj);
+ ptr = na_get_pointer_for_read(obj);
+ pos = na_get_offset(obj);
+ <% find_tmpl("store").definitions.select{|x| x.class==Store}.each do |x| %>
+ if (<%=x.condition("klass")%>) {
+ <%=x.extract_data("ptr","pos","x")%>;
+ return x;
+ }
+ <% end %>
+
+ // coerce
+ r = rb_funcall(obj, rb_intern("coerce_cast"), 1, cT);
+ if (CLASS_OF(r)==cT) {
+ return <%=c_func%>(r);
+ }
+ <% if is_object %>
+ return obj;
+ <% else %>
+ rb_raise(nary_eCastError, "unknown conversion from %s to %s",
+ rb_class2name(CLASS_OF(obj)),
+ rb_class2name(cT));
+ <% end %>
+ }
+ if (TYPE(obj)==T_ARRAY) {
+ if (RARRAY_LEN(obj) != 1) {
+ rb_raise(nary_eShapeError,"array size should be 1");
+ }
+ return m_num_to_data(RARRAY_AREF(obj,0));
+ }
+ return m_num_to_data(obj);
+}
diff --git a/ext/numo/narray/gen/tmpl/eye.c b/ext/numo/narray/gen/tmpl/eye.c
new file mode 100644
index 0000000..b4b04f5
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/eye.c
@@ -0,0 +1,91 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t n0, n1;
+ size_t i0, i1;
+ ssize_t s0, s1;
+ char *p0, *p1;
+ char *g;
+ ssize_t kofs;
+ dtype data;
+
+ g = (char*)(lp->opt_ptr);
+ kofs = *(ssize_t*)g;
+ data = *(dtype*)(g+sizeof(ssize_t));
+
+ n0 = lp->args[0].shape[0];
+ n1 = lp->args[0].shape[1];
+ s0 = lp->args[0].iter[0].step;
+ s1 = lp->args[0].iter[1].step;
+ p0 = NDL_PTR(lp,0);
+
+ for (i0=0; i0 < n0; i0++) {
+ p1 = p0;
+ for (i1=0; i1 < n1; i1++) {
+ *(dtype*)p1 = (i0+kofs==i1) ? data : m_zero;
+ p1 += s1;
+ }
+ p0 += s0;
+ }
+}
+
+/*
+ Eye: Set a value to diagonal components, set 0 to non-diagonal components.
+ @overload <%=name%>([element,offset])
+ @param [Numeric] element Diagonal element to be stored. Default is 1.
+ @param [Integer] offset Diagonal offset from the main diagonal. The
+ default is 0. k>0 for diagonals above the main diagonal, and k<0
+ for diagonals below the main diagonal.
+ @return [Numo::<%=class_name%>] <%=name%> of self.
+*/
+static VALUE
+<%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
+{
+ ndfunc_arg_in_t ain[1] = {{OVERWRITE,2}};
+ ndfunc_t ndf = {<%=c_iter%>, NO_LOOP, 1,0, ain,0};
+ ssize_t kofs;
+ dtype data;
+ char *g;
+ int nd;
+ narray_t *na;
+
+ // check arguments
+ if (argc > 2) {
+ rb_raise(rb_eArgError,"too many arguments (%d for 0..2)",argc);
+ } else if (argc == 2) {
+ data = m_num_to_data(argv[0]);
+ kofs = NUM2SSIZET(argv[1]);
+ } else if (argc == 1) {
+ data = m_num_to_data(argv[0]);
+ kofs = 0;
+ } else {
+ data = m_one;
+ kofs = 0;
+ }
+
+ GetNArray(self,na);
+ nd = na->ndim;
+ if (nd < 2) {
+ rb_raise(nary_eDimensionError,"less than 2-d array");
+ }
+
+ // Diagonal offset from the main diagonal.
+ if (kofs >= 0) {
+ if ((size_t)(kofs) >= na->shape[nd-1]) {
+ rb_raise(rb_eArgError,"invalid diagonal offset(%"SZF"d) for "
+ "last dimension size(%"SZF"d)",kofs,na->shape[nd-1]);
+ }
+ } else {
+ if ((size_t)(-kofs) >= na->shape[nd-2]) {
+ rb_raise(rb_eArgError,"invalid diagonal offset(%"SZF"d) for "
+ "last-1 dimension size(%"SZF"d)",kofs,na->shape[nd-2]);
+ }
+ }
+
+ g = ALLOCA_N(char,sizeof(ssize_t)+sizeof(dtype));
+ *(ssize_t*)g = kofs;
+ *(dtype*)(g+sizeof(ssize_t)) = data;
+
+ na_ndloop3(&ndf, g, 1, self);
+ return self;
+}
diff --git a/ext/numo/narray/gen/tmpl/fill.c b/ext/numo/narray/gen/tmpl/fill.c
new file mode 100644
index 0000000..6c26171
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/fill.c
@@ -0,0 +1,38 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ char *p1;
+ ssize_t s1;
+ size_t *idx1;
+ VALUE x = lp->option;
+ dtype y;
+ INIT_COUNTER(lp, i);
+ INIT_PTR_IDX(lp, 0, p1, s1, idx1);
+ y = m_num_to_data(x);
+ if (idx1) {
+ for (; i--;) {
+ SET_DATA_INDEX(p1,idx1,dtype,y);
+ }
+ } else {
+ for (; i--;) {
+ SET_DATA_STRIDE(p1,s1,dtype,y);
+ }
+ }
+}
+
+/*
+ Fill elements with other.
+ @overload <%=name%> other
+ @param [Numeric] other
+ @return [Numo::<%=class_name%>] self.
+*/
+static VALUE
+<%=c_func(1)%>(VALUE self, VALUE val)
+{
+ ndfunc_arg_in_t ain[2] = {{OVERWRITE,0},{sym_option}};
+ ndfunc_t ndf = { <%=c_iter%>, FULL_LOOP, 2, 0, ain, 0 };
+
+ na_ndloop(&ndf, 2, self, val);
+ return self;
+}
diff --git a/ext/numo/narray/gen/tmpl/format.c b/ext/numo/narray/gen/tmpl/format.c
new file mode 100644
index 0000000..e7ef9f0
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/format.c
@@ -0,0 +1,60 @@
+static VALUE
+format_<%=type_name%>(VALUE fmt, dtype* x)
+{
+ // fix-me
+ char s[48];
+ int n;
+
+ if (NIL_P(fmt)) {
+ n = m_sprintf(s,*x);
+ return rb_str_new(s,n);
+ }
+ return rb_funcall(fmt, '%', 1, m_data_to_num(*x));
+}
+
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ char *p1, *p2;
+ ssize_t s1, s2;
+ size_t *idx1;
+ dtype *x;
+ VALUE y;
+ VALUE fmt = lp->option;
+ INIT_COUNTER(lp, i);
+ INIT_PTR_IDX(lp, 0, p1, s1, idx1);
+ INIT_PTR(lp, 1, p2, s2);
+ if (idx1) {
+ for (; i--;) {
+ x = (dtype*)(p1+*idx1); idx1++;
+ y = format_<%=type_name%>(fmt, x);
+ SET_DATA_STRIDE(p2, s2, VALUE, y);
+ }
+ } else {
+ for (; i--;) {
+ x = (dtype*)p1; p1+=s1;
+ y = format_<%=type_name%>(fmt, x);
+ SET_DATA_STRIDE(p2, s2, VALUE, y);
+ }
+ }
+}
+
+/*
+ Format elements into strings.
+ @overload <%=name%> format
+ @param [String] format
+ @return [Numo::RObject] array of formated strings.
+*/
+static VALUE
+<%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
+{
+ VALUE fmt=Qnil;
+
+ ndfunc_arg_in_t ain[2] = {{Qnil,0},{sym_option}};
+ ndfunc_arg_out_t aout[1] = {{numo_cRObject,0}};
+ ndfunc_t ndf = { <%=c_iter%>, FULL_LOOP_NIP, 2, 1, ain, aout };
+
+ rb_scan_args(argc, argv, "01", &fmt);
+ return na_ndloop(&ndf, 2, self, fmt);
+}
diff --git a/ext/numo/narray/gen/tmpl/format_to_a.c b/ext/numo/narray/gen/tmpl/format_to_a.c
new file mode 100644
index 0000000..7676814
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/format_to_a.c
@@ -0,0 +1,47 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ char *p1;
+ ssize_t s1;
+ size_t *idx1;
+ dtype *x;
+ VALUE y;
+ volatile VALUE a;
+ VALUE fmt = lp->option;
+ INIT_COUNTER(lp, i);
+ INIT_PTR_IDX(lp, 0, p1, s1, idx1);
+ a = rb_ary_new2(i);
+ rb_ary_push(lp->args[1].value, a);
+ if (idx1) {
+ for (; i--;) {
+ x = (dtype*)(p1 + *idx1); idx1++;
+ y = format_<%=type_name%>(fmt, x);
+ rb_ary_push(a,y);
+ }
+ } else {
+ for (; i--;) {
+ x = (dtype*)p1; p1+=s1;
+ y = format_<%=type_name%>(fmt, x);
+ rb_ary_push(a,y);
+ }
+ }
+}
+
+/*
+ Format elements into strings.
+ @overload <%=name%> format
+ @param [String] format
+ @return [Array] array of formated strings.
+*/
+static VALUE
+<%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
+{
+ volatile VALUE fmt=Qnil;
+ ndfunc_arg_in_t ain[3] = {{Qnil,0},{sym_loop_opt},{sym_option}};
+ ndfunc_arg_out_t aout[1] = {{rb_cArray,0}}; // dummy?
+ ndfunc_t ndf = { <%=c_iter%>, FULL_LOOP_NIP, 3, 1, ain, aout };
+
+ rb_scan_args(argc, argv, "01", &fmt);
+ return na_ndloop_cast_narray_to_rarray(&ndf, self, fmt);
+}
diff --git a/ext/numo/narray/gen/tmpl/frexp.c b/ext/numo/narray/gen/tmpl/frexp.c
new file mode 100644
index 0000000..1dde9a2
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/frexp.c
@@ -0,0 +1,37 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ char *p1, *p2, *p3;
+ ssize_t s1, s2, s3;
+ dtype x;
+ int y;
+ INIT_COUNTER(lp, i);
+ INIT_PTR(lp, 0, p1, s1);
+ INIT_PTR(lp, 1, p2, s2);
+ INIT_PTR(lp, 2, p3, s3);
+ for (; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ x = m_<%=name%>(x,&y);
+ SET_DATA_STRIDE(p2,s2,dtype,x);
+ SET_DATA_STRIDE(p3,s3,int32_t,y);
+ }
+}
+
+/*
+ split the number x into a normalized fraction and an exponent.
+ Returns [mantissa, exponent], where x = mantissa * 2**exponent.
+
+ @overload <%=name%>(x)
+ @param [Numo::NArray,Numeric] x
+ @return [Numo::<%=class_name%>,Numo::Int32] mantissa and exponent.
+
+*/
+static VALUE
+<%=c_func(1)%>(VALUE mod, VALUE a1)
+{
+ ndfunc_arg_in_t ain[1] = {{cT,0}};
+ ndfunc_arg_out_t aout[2] = {{cT,0},{numo_cInt32,0}};
+ ndfunc_t ndf = { <%=c_iter%>, STRIDE_LOOP, 1,2, ain,aout };
+ return na_ndloop(&ndf, 1, a1);
+}
diff --git a/ext/numo/narray/gen/tmpl/init_class.c b/ext/numo/narray/gen/tmpl/init_class.c
new file mode 100644
index 0000000..aa1d014
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/init_class.c
@@ -0,0 +1,20 @@
+ /*
+ Document-class: <%= full_class_name %>
+ <%= description %>
+ */
+ cT = rb_define_class_under(<%=ns_var%>, "<%=class_name%>", cNArray);
+
+ <% for x in class_alias %>
+ // alias of <%=class_name%>
+ rb_define_const(<%=ns_var%>, "<%=x%>", <%=type_var%>);
+ <% end %>
+
+ hCast = rb_hash_new();
+ rb_define_const(cT, "UPCAST", hCast);
+ rb_hash_aset(hCast, rb_cArray, cT);
+ <% for x in upcast %>
+ <%= x %><% end %>
+
+ <% @children.each do |m| %>
+ <%= m.init_def %><% end %>
+ rb_define_singleton_method(cT, "[]", <%=find("cast").c_func%>, -2);
diff --git a/ext/numo/narray/gen/tmpl/init_module.c b/ext/numo/narray/gen/tmpl/init_module.c
new file mode 100644
index 0000000..17672f5
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/init_module.c
@@ -0,0 +1,12 @@
+ /*
+ Document-module: <%= full_module_name %>
+ <%= description %>
+ */
+ <% if module_var != ns_var %>
+ <%=module_var%> = rb_define_module_under(<%=ns_var%>, "<%=module_name%>");
+ <% end %>
+ <% @children.each do |m| %>
+ <%= m.init_def %><% end %>
+
+ // how to do this?
+ //rb_extend_object(cT, mTM);
diff --git a/ext/numo/narray/gen/tmpl/inspect.c b/ext/numo/narray/gen/tmpl/inspect.c
new file mode 100644
index 0000000..d32afe3
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/inspect.c
@@ -0,0 +1,20 @@
+static VALUE
+<%=c_iter%>(char *ptr, size_t pos, VALUE fmt)
+{
+<% if is_object %>
+ return rb_inspect(*(VALUE*)(ptr+pos));
+<% else %>
+ return format_<%=type_name%>(fmt, (dtype*)(ptr+pos));
+<% end %>
+}
+
+/*
+ Returns a string containing a human-readable representation of NArray.
+ @overload inspect
+ @return [String]
+*/
+VALUE
+<%=c_func(0)%>(VALUE ary)
+{
+ return na_ndloop_inspect(ary, <%=c_iter%>, Qnil);
+}
diff --git a/ext/numo/narray/gen/tmpl/lib.c b/ext/numo/narray/gen/tmpl/lib.c
new file mode 100644
index 0000000..14354c3
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/lib.c
@@ -0,0 +1,45 @@
+/*
+ <%= file_name %>
+ Ruby/Numo::GSL - GSL wrapper for Ruby/Numo::NArray
+
+ created on: 2017-03-11
+ Copyright (C) 2017 Masahiro Tanaka
+*/
+
+#include <ruby.h>
+#include <assert.h>
+#include "numo/narray.h"
+#include "numo/template.h"
+#include "SFMT.h"
+
+#define m_map(x) m_num_to_data(rb_yield(m_data_to_num(x)))
+
+<% id_decl.each do |x| %>
+<%= x %>
+<% end %>
+
+<% include_files.each do |f| %>
+#include <<%=f%>>
+<% end %>
+
+VALUE cT;
+extern VALUE cRT;
+
+<% children.each do |c|%>
+<%= c.result+"\n\n" %>
+<% end %>
+
+void
+Init_<%=lib_name%>(void)
+{
+ VALUE hCast, <%=ns_var%>;
+
+ <%=ns_var%> = rb_define_module("Numo");
+
+ <% id_assign.each do |x| %>
+ <%= x %><% end %>
+
+<% children.each do |c| %>
+<%= c.init_def %>
+<% end %>
+}
diff --git a/ext/numo/narray/gen/tmpl/logseq.c b/ext/numo/narray/gen/tmpl/logseq.c
new file mode 100644
index 0000000..84930c8
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/logseq.c
@@ -0,0 +1,82 @@
+typedef struct {
+ seq_data_t beg;
+ seq_data_t step;
+ seq_data_t base;
+ seq_count_t count;
+} logseq_opt_t;
+
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ char *p1;
+ ssize_t s1;
+ size_t *idx1;
+ dtype x;
+ seq_data_t beg, step, base;
+ seq_count_t c;
+ logseq_opt_t *g;
+
+ INIT_COUNTER(lp, i);
+ INIT_PTR_IDX(lp, 0, p1, s1, idx1);
+ g = (logseq_opt_t*)(lp->opt_ptr);
+ beg = g->beg;
+ step = g->step;
+ base = g->base;
+ c = g->count;
+ if (idx1) {
+ for (; i--;) {
+ x = f_seq(beg,step,c++);
+ *(dtype*)(p1+*idx1) = m_pow(base,x);
+ idx1++;
+ }
+ } else {
+ for (; i--;) {
+ x = f_seq(beg,step,c++);
+ *(dtype*)(p1) = m_pow(base,x);
+ p1 += s1;
+ }
+ }
+ g->count = c;
+}
+
+/*
+ Set logarithmic sequence of numbers to self. The sequence is obtained from
+ base**(beg+i*step)
+ where i is 1-dimensional index.
+ Applicable classes: DFloat, SFloat, DComplex, SCopmplex.
+
+ @overload logseq(beg,step,[base])
+ @param [Numeric] beg The begining of sequence.
+ @param [Numeric] step The step of sequence.
+ @param [Numeric] base The base of log space. (default=10)
+ @return [Numo::<%=class_name%>] self.
+
+ @example
+ Numo::DFloat.new(5).logseq(4,-1,2)
+ => Numo::DFloat#shape=[5]
+ [16, 8, 4, 2, 1]
+ Numo::DComplex.new(5).logseq(0,1i*Math::PI/3,Math::E)
+ => Numo::DComplex#shape=[5]
+ [1+7.26156e-310i, 0.5+0.866025i, -0.5+0.866025i, -1+1.22465e-16i, ...]
+*/
+static VALUE
+<%=c_func(-1)%>(int argc, VALUE *args, VALUE self)
+{
+ logseq_opt_t *g;
+ VALUE vbeg, vstep, vbase;
+ ndfunc_arg_in_t ain[1] = {{OVERWRITE,0}};
+ ndfunc_t ndf = {<%=c_iter%>, FULL_LOOP, 1,0, ain,0};
+
+ g = ALLOCA_N(logseq_opt_t,1);
+ rb_scan_args(argc, args, "21", &vbeg, &vstep, &vbase);
+ g->beg = m_num_to_data(vbeg);
+ g->step = m_num_to_data(vstep);
+ if (vbase==Qnil) {
+ g->base = m_from_real(10);
+ } else {
+ g->base = m_num_to_data(vbase);
+ }
+ na_ndloop3(&ndf, g, 1, self);
+ return self;
+}
diff --git a/ext/numo/narray/gen/tmpl/map_with_index.c b/ext/numo/narray/gen/tmpl/map_with_index.c
new file mode 100644
index 0000000..58c55f5
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/map_with_index.c
@@ -0,0 +1,94 @@
+static inline dtype
+yield_map_with_index(dtype x, size_t *c, VALUE *a, int nd, int md)
+{
+ int j;
+ VALUE y;
+
+ a[0] = m_data_to_num(x);
+ for (j=0; j<=nd; j++) {
+ a[j+1] = SIZET2NUM(c[j]);
+ }
+ y = rb_yield(rb_ary_new4(md,a));
+ return m_num_to_data(y);
+}
+
+void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ char *p1, *p2;
+ ssize_t s1, s2;
+ size_t *idx1, *idx2;
+ dtype x;
+ VALUE *a;
+ size_t *c;
+ int nd, md;
+
+ c = (size_t*)(lp->opt_ptr);
+ nd = lp->ndim - 1;
+ md = lp->ndim + 1;
+ a = ALLOCA_N(VALUE,md);
+
+ INIT_COUNTER(lp, i);
+ INIT_PTR_IDX(lp, 0, p1, s1, idx1);
+ INIT_PTR_IDX(lp, 1, p2, s2, idx2);
+
+ c[nd] = 0;
+ if (idx1) {
+ if (idx2) {
+ for (; i--;) {
+ GET_DATA_INDEX(p1,idx1,dtype,x);
+ x = yield_map_with_index(x,c,a,nd,md);
+ SET_DATA_INDEX(p2,idx2,dtype,x);
+ c[nd]++;
+ }
+ } else {
+ for (; i--;) {
+ GET_DATA_INDEX(p1,idx1,dtype,x);
+ x = yield_map_with_index(x,c,a,nd,md);
+ SET_DATA_STRIDE(p2,s2,dtype,x);
+ c[nd]++;
+ }
+ }
+ } else {
+ if (idx2) {
+ for (; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ x = yield_map_with_index(x,c,a,nd,md);
+ SET_DATA_INDEX(p2,idx2,dtype,x);
+ c[nd]++;
+ }
+ } else {
+ for (; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ x = yield_map_with_index(x,c,a,nd,md);
+ SET_DATA_STRIDE(p2,s2,dtype,x);
+ c[nd]++;
+ }
+ }
+ }
+}
+
+/*
+ Invokes the given block once for each element of self,
+ passing that element and indices along each axis as parameters.
+ Creates a new NArray containing the values returned by the block.
+ Inplace option is allowed, i.e., `nary.inplace.map` overwrites `nary`.
+
+ @overload <%=name%>
+
+ For a block {|x,i,j,...| ... }
+ @yield [x,i,j,...] x is an element, i,j,... are multidimensional indices.
+
+ @return [Numo::NArray] mapped array
+
+*/
+static VALUE
+<%=c_func(0)%>(VALUE self)
+{
+ ndfunc_arg_in_t ain[1] = {{Qnil,0}};
+ ndfunc_arg_out_t aout[1] = {{cT,0}};
+ ndfunc_t ndf = {<%=c_iter%>, FULL_LOOP, 1,1, ain,aout};
+
+ return na_ndloop_with_index(&ndf, 1, self);
+}
diff --git a/ext/numo/narray/gen/tmpl/median.c b/ext/numo/narray/gen/tmpl/median.c
new file mode 100644
index 0000000..bf821b9
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/median.c
@@ -0,0 +1,64 @@
+<% (is_float ? ["_ignan","_prnan"] : [""]).each do |j| %>
+static void
+<%=c_iter%><%=j%>(na_loop_t *const lp)
+{
+ size_t n;
+ char *p1, *p2;
+ dtype *buf;
+
+ INIT_COUNTER(lp, n);
+ p1 = (lp->args[0]).ptr + (lp->args[0].iter[0]).pos;
+ p2 = (lp->args[1]).ptr + (lp->args[1].iter[0]).pos;
+ buf = (dtype*)p1;
+
+ <%=type_name%>_qsort<%=j%>(buf, n, sizeof(dtype));
+
+ <% if is_float %>
+ for (; n; n--) {
+ if (!isnan(buf[n-1])) break;
+ }
+ <% end %>
+
+ if (n==0) {
+ *(dtype*)p2 = buf[0];
+ }
+ else if (n%2==0) {
+ *(dtype*)p2 = (buf[n/2-1]+buf[n/2])/2;
+ }
+ else {
+ *(dtype*)p2 = buf[(n-1)/2];
+ }
+}
+<% end %>
+
+/*
+ <%=name%> of self.
+<% if is_float %>
+ @overload <%=name%>(axis:nil, keepdims:false, nan:false)
+ @param [TrueClass] nan (keyword) If true, propagete NaN. If false, ignore NaN.
+<% else %>
+ @overload <%=name%>(axis:nil, keepdims:false)
+<% end %>
+ @param [Numeric,Array,Range] axis (keyword) Affected dimensions.
+ @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in the result array as dimensions with size one.
+ @return [Numo::<%=class_name%>] returns <%=name%> of self.
+*/
+
+static VALUE
+<%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
+{
+ VALUE reduce;
+ ndfunc_arg_in_t ain[2] = {{OVERWRITE,0},{sym_reduce,0}};
+ ndfunc_arg_out_t aout[1] = {{INT2FIX(0),0}};
+ ndfunc_t ndf = {0, NDF_HAS_LOOP|NDF_FLAT_REDUCE, 2,1, ain,aout};
+
+ self = na_copy(self); // as temporary buffer
+ <% if is_float %>
+ ndf.func = <%=c_iter%>_ignan;
+ reduce = na_reduce_dimension(argc, argv, 1, &self, &ndf, <%=c_iter%>_prnan);
+ <% else %>
+ ndf.func = <%=c_iter%>;
+ reduce = na_reduce_dimension(argc, argv, 1, &self, &ndf, 0);
+ <% end %>
+ return na_ndloop(&ndf, 2, self, reduce);
+}
diff --git a/ext/numo/narray/gen/tmpl/minmax.c b/ext/numo/narray/gen/tmpl/minmax.c
new file mode 100644
index 0000000..e15b56d
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/minmax.c
@@ -0,0 +1,46 @@
+<% (is_float ? ["","_nan"] : [""]).each do |j| %>
+static void
+<%=c_iter%><%=j%>(na_loop_t *const lp)
+{
+ size_t n;
+ char *p1;
+ ssize_t s1;
+ dtype xmin,xmax;
+
+ INIT_COUNTER(lp, n);
+ INIT_PTR(lp, 0, p1, s1);
+
+ f_<%=name%><%=j%>(n,p1,s1,&xmin,&xmax);
+
+ *(dtype*)(lp->args[1].ptr + lp->args[1].iter[0].pos) = xmin;
+ *(dtype*)(lp->args[2].ptr + lp->args[2].iter[0].pos) = xmax;
+}
+<% end %>
+
+/*
+ <%=name%> of self.
+<% if is_float %>
+ @overload <%=name%>(axis:nil, keepdims:false, nan:false)
+ @param [TrueClass] nan If true, apply NaN-aware algorithm (return NaN if exist).
+<% else %>
+ @overload <%=name%>(axis:nil, keepdims:false)
+<% end %>
+ @param [Numeric,Array,Range] axis (keyword) Affected dimensions.
+ @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in the result array as dimensions with size one.
+ @return [Numo::<%=class_name%>,Numo::<%=class_name%>] min and max of self.
+*/
+static VALUE
+<%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
+{
+ VALUE reduce;
+ ndfunc_arg_in_t ain[2] = {{cT,0},{sym_reduce,0}};
+ ndfunc_arg_out_t aout[2] = {{cT,0},{cT,0}};
+ ndfunc_t ndf = {<%=c_iter%>, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT, 2,2, ain,aout};
+
+ <% if is_float %>
+ reduce = na_reduce_dimension(argc, argv, 1, &self, &ndf, <%=c_iter%>_nan);
+ <% else %>
+ reduce = na_reduce_dimension(argc, argv, 1, &self, &ndf, 0);
+ <% end %>
+ return na_ndloop(&ndf, 2, self, reduce);
+}
diff --git a/ext/numo/narray/gen/tmpl/module.c b/ext/numo/narray/gen/tmpl/module.c
new file mode 100644
index 0000000..5d066bb
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/module.c
@@ -0,0 +1,9 @@
+/*
+ module definition: <%= full_module_name %>
+*/
+
+<% if module_var != ns_var %>
+VALUE <%=module_var%>;
+<% end %>
+
+<%= method_code %>
diff --git a/ext/numo/narray/gen/tmpl/new_dim0.c b/ext/numo/narray/gen/tmpl/new_dim0.c
new file mode 100644
index 0000000..0fe8a40
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/new_dim0.c
@@ -0,0 +1,12 @@
+static VALUE
+<%=c_func(:nodef)%>(dtype x)
+{
+ VALUE v;
+ dtype *ptr;
+
+ v = nary_new(cT, 0, NULL);
+ ptr = (dtype*)(char*)na_get_pointer_for_write(v);
+ *ptr = x;
+ na_release_lock(v);
+ return v;
+}
diff --git a/ext/numo/narray/gen/tmpl/poly.c b/ext/numo/narray/gen/tmpl/poly.c
new file mode 100644
index 0000000..f2282c5
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/poly.c
@@ -0,0 +1,49 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ dtype x, y, a;
+
+ x = *(dtype*)(lp->args[0].ptr + lp->args[0].iter[0].pos);
+ i = lp->narg - 2;
+ y = *(dtype*)(lp->args[i].ptr + lp->args[i].iter[0].pos);
+ for (; --i;) {
+ y = m_mul(x,y);
+ a = *(dtype*)(lp->args[i].ptr + lp->args[i].iter[0].pos);
+ y = m_add(y,a);
+ }
+ i = lp->narg - 1;
+ *(dtype*)(lp->args[i].ptr + lp->args[i].iter[0].pos) = y;
+}
+
+/*
+ Polynomial.: a0 + a1*x + a2*x**2 + a3*x**3 + ... + an*x**n
+ @overload <%=name%> a0, a1, ...
+ @param [Numo::NArray,Numeric] a0
+ @param [Numo::NArray,Numeric] a1 , ...
+ @return [Numo::<%=class_name%>]
+*/
+static VALUE
+<%=c_func(-2)%>(VALUE self, VALUE args)
+{
+ int argc, i;
+ VALUE *argv;
+ volatile VALUE v, a;
+ ndfunc_arg_out_t aout[1] = {{cT,0}};
+ ndfunc_t ndf = { <%=c_iter%>, NO_LOOP, 0, 1, 0, aout };
+
+ argc = RARRAY_LEN(args);
+ ndf.nin = argc+1;
+ ndf.ain = ALLOCA_N(ndfunc_arg_in_t,argc+1);
+ for (i=0; i<argc+1; i++) {
+ ndf.ain[i].type = cT;
+ }
+ argv = ALLOCA_N(VALUE,argc+1);
+ argv[0] = self;
+ for (i=0; i<argc; i++) {
+ argv[i+1] = RARRAY_PTR(args)[i];
+ }
+ a = rb_ary_new4(argc+1, argv);
+ v = na_ndloop2(&ndf, a);
+ return <%=type_name%>_extract(v);
+}
diff --git a/ext/numo/narray/gen/tmpl/pow.c b/ext/numo/narray/gen/tmpl/pow.c
new file mode 100644
index 0000000..0d43bc6
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/pow.c
@@ -0,0 +1,78 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ char *p1, *p2, *p3;
+ ssize_t s1, s2, s3;
+ dtype x, y;
+ INIT_COUNTER(lp, i);
+ INIT_PTR(lp, 0, p1, s1);
+ INIT_PTR(lp, 1, p2, s2);
+ INIT_PTR(lp, 2, p3, s3);
+ for (; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ GET_DATA_STRIDE(p2,s2,dtype,y);
+ x = m_pow(x,y);
+ SET_DATA_STRIDE(p3,s3,dtype,x);
+ }
+}
+
+static void
+<%=c_iter%>_int32(na_loop_t *const lp)
+{
+ size_t i;
+ char *p1, *p2, *p3;
+ ssize_t s1, s2, s3;
+ dtype x;
+ int32_t y;
+ INIT_COUNTER(lp, i);
+ INIT_PTR(lp, 0, p1, s1);
+ INIT_PTR(lp, 1, p2, s2);
+ INIT_PTR(lp, 2, p3, s3);
+ for (; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ GET_DATA_STRIDE(p2,s2,int32_t,y);
+ x = m_pow_int(x,y);
+ SET_DATA_STRIDE(p3,s3,dtype,x);
+ }
+}
+
+static VALUE
+<%=c_func%>_self(VALUE self, VALUE other)
+{
+ ndfunc_arg_in_t ain[2] = {{cT,0},{cT,0}};
+ ndfunc_arg_in_t ain_i[2] = {{cT,0},{numo_cInt32,0}};
+ ndfunc_arg_out_t aout[1] = {{cT,0}};
+ ndfunc_t ndf = { <%=c_iter%>, STRIDE_LOOP, 2, 1, ain, aout };
+ ndfunc_t ndf_i = { <%=c_iter%>_int32, STRIDE_LOOP, 2, 1, ain_i, aout };
+
+ // fixme : use na.integer?
+ if (FIXNUM_P(other) || rb_obj_is_kind_of(other,numo_cInt32)) {
+ return na_ndloop(&ndf_i, 2, self, other);
+ } else {
+ return na_ndloop(&ndf, 2, self, other);
+ }
+}
+
+/*
+ Binary power.
+ @overload <%=op_map%> other
+ @param [Numo::NArray,Numeric] other
+ @return [Numo::NArray] self to the other-th power.
+*/
+static VALUE
+<%=c_func(1)%>(VALUE self, VALUE other)
+{
+ <% if is_object %>
+ return <%=c_func%>_self(self,other);
+ <% else %>
+ VALUE klass, v;
+ klass = na_upcast(CLASS_OF(self),CLASS_OF(other));
+ if (klass==cT) {
+ return <%=c_func%>_self(self,other);
+ } else {
+ v = rb_funcall(klass, id_cast, 1, self);
+ return rb_funcall(v, id_pow, 1, other);
+ }
+ <% end %>
+}
diff --git a/ext/numo/narray/gen/tmpl/powint.c b/ext/numo/narray/gen/tmpl/powint.c
new file mode 100644
index 0000000..2125ad3
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/powint.c
@@ -0,0 +1,17 @@
+static dtype pow_<%=type_name%>(dtype x, int p)
+{
+ dtype r = m_one;
+ switch(p) {
+ case 2: return m_square(x);
+ case 3: return m_mul(m_square(x),x);
+ case 1: return x;
+ case 0: return m_one;
+ }
+ if (p<0) return m_zero;
+ while (p) {
+ if ((p%2) == 1) r = m_mul(r,x);
+ x = m_square(x);
+ p /= 2;
+ }
+ return r;
+}
diff --git a/ext/numo/narray/gen/tmpl/qsort.c b/ext/numo/narray/gen/tmpl/qsort.c
new file mode 100644
index 0000000..2be8b1d
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/qsort.c
@@ -0,0 +1,150 @@
+/*
+ qsort.c
+ Numerical Array Extension for Ruby
+ modified by Masahiro TANAKA
+*/
+
+/*
+ * qsort.c: standard quicksort algorithm
+ *
+ * Modifications from vanilla NetBSD source:
+ * Add do ... while() macro fix
+ * Remove __inline, _DIAGASSERTs, __P
+ * Remove ill-considered "swap_cnt" switch to insertion sort,
+ * in favor of a simple check for presorted input.
+ *
+ * CAUTION: if you change this file, see also qsort_arg.c
+ *
+ * $PostgreSQL: pgsql/src/port/qsort.c,v 1.12 2006/10/19 20:56:22 tgl Exp $
+ */
+
+/* $NetBSD: qsort.c,v 1.13 2003/08/07 16:43:42 agc Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef QSORT_INCL
+#define QSORT_INCL
+#define Min(x, y) ((x) < (y) ? (x) : (y))
+
+#define swap(type,a,b) \
+ do {type tmp=*(type*)(a); *(type*)(a)=*(type*)(b); *(type*)(b)=tmp;} while(0)
+
+#define vecswap(type, a, b, n) if ((n)>0) swap(type,(a),(b))
+
+#define MED3(a,b,c) \
+ (cmpgt(b,a) ? \
+ (cmpgt(c,b) ? b : (cmpgt(c,a) ? c : a)) \
+ : (cmpgt(b,c) ? b : (cmpgt(c,a) ? a : c)))
+#endif
+
+#undef qsort_dtype
+#define qsort_dtype <%=dtype%>
+#undef qsort_cast
+#define qsort_cast <%=dcast%>
+<% if "#{suffix}" != "" %>
+#undef cmp
+#undef cmpgt
+#define cmp(a,b) cmp<%=suffix%>(a,b)
+#define cmpgt(a,b) cmpgt<%=suffix%>(a,b)
+<% end %>
+<% c_func(:nodef)%>
+
+void
+<%=type_name%>_qsort<%=suffix%>(void *a, size_t n, ssize_t es)
+{
+ char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
+ int d, r, presorted;
+
+ loop:
+ if (n < 7) {
+ for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
+ for (pl = pm; pl > (char *) a && cmpgt(pl - es, pl);
+ pl -= es)
+ swap(qsort_dtype, pl, pl - es);
+ return;
+ }
+ presorted = 1;
+ for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es) {
+ if (cmpgt(pm - es, pm)) {
+ presorted = 0;
+ break;
+ }
+ }
+ if (presorted)
+ return;
+ pm = (char *) a + (n / 2) * es;
+ if (n > 7) {
+ pl = (char *) a;
+ pn = (char *) a + (n - 1) * es;
+ if (n > 40) {
+ d = (n / 8) * es;
+ pl = MED3(pl, pl + d, pl + 2 * d);
+ pm = MED3(pm - d, pm, pm + d);
+ pn = MED3(pn - 2 * d, pn - d, pn);
+ }
+ pm = MED3(pl, pm, pn);
+ }
+ swap(qsort_dtype, a, pm);
+ pa = pb = (char *) a + es;
+ pc = pd = (char *) a + (n - 1) * es;
+ for (;;) {
+ while (pb <= pc && (r = cmp(pb, a)) <= 0) {
+ if (r == 0) {
+ swap(qsort_dtype, pa, pb);
+ pa += es;
+ }
+ pb += es;
+ }
+ while (pb <= pc && (r = cmp(pc, a)) >= 0) {
+ if (r == 0) {
+ swap(qsort_dtype, pc, pd);
+ pd -= es;
+ }
+ pc -= es;
+ }
+ if (pb > pc)
+ break;
+ swap(qsort_dtype, pb, pc);
+ pb += es;
+ pc -= es;
+ }
+ pn = (char *) a + n * es;
+ r = Min(pa - (char *) a, pb - pa);
+ vecswap(qsort_dtype, a, pb - r, r);
+ r = Min(pd - pc, pn - pd - es);
+ vecswap(qsort_dtype, pb, pn - r, r);
+ if ((r = pb - pa) > es)
+ <%=type_name%>_qsort<%=suffix%>(a, r / es, es);
+ if ((r = pd - pc) > es) {
+ a = pn - r;
+ n = r / es;
+ goto loop;
+ }
+}
diff --git a/ext/numo/narray/gen/tmpl/rand.c b/ext/numo/narray/gen/tmpl/rand.c
new file mode 100644
index 0000000..d3ede6b
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/rand.c
@@ -0,0 +1,165 @@
+<%
+if is_int && !is_object
+ if /Int64$/ =~ class_name
+ rand_bit = 64
+ else
+ rand_bit = 32
+ end
+ m_rand = "m_rand(max,shift)"
+ shift_def = "int shift;"
+ shift_set = "shift = #{rand_bit-1} - msb_pos(max);"
+ rand_type = "uint#{rand_bit}_t"
+%>
+
+#define HWID (sizeof(dtype)*4)
+
+static int msb_pos(<%=rand_type%> a)
+{
+ int width = HWID;
+ int pos = 0;
+ <%=rand_type%> mask = (((dtype)1 << HWID)-1) << HWID;
+
+ if (a==0) {return -1;}
+
+ while (width) {
+ if (a & mask) {
+ pos += width;
+ } else {
+ mask >>= width;
+ }
+ width >>= 1;
+ mask &= mask << width;
+ }
+ return pos;
+}
+
+/* generates a random number on [0,max) */
+<% if rand_bit == 64 %>
+inline static dtype m_rand(uint64_t max, int shift)
+{
+ uint64_t x;
+ do {
+ x = gen_rand32();
+ x <<= 32;
+ x |= gen_rand32();
+ x >>= shift;
+ } while (x >= max);
+ return x;
+}
+<% else %>
+inline static dtype m_rand(uint32_t max, int shift)
+{
+ uint32_t x;
+ do {
+ x = gen_rand32();
+ x >>= shift;
+ } while (x >= max);
+ return x;
+}
+<% end %>
+<%
+else
+ m_rand = "m_rand(max)"
+ shift_def = ""
+ shift_set = ""
+ rand_type = "dtype"
+end
+%>
+
+typedef struct {
+ dtype low;
+ <%=rand_type%> max;
+} rand_opt_t;
+
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ char *p1;
+ ssize_t s1;
+ size_t *idx1;
+ dtype x;
+ rand_opt_t *g;
+ dtype low;
+ <%=rand_type%> max;
+ <%=shift_def%>
+
+ INIT_COUNTER(lp, i);
+ INIT_PTR_IDX(lp, 0, p1, s1, idx1);
+ g = (rand_opt_t*)(lp->opt_ptr);
+ low = g->low;
+ max = g->max;
+ <%=shift_set%>
+
+ if (idx1) {
+ for (; i--;) {
+ x = m_add(<%=m_rand%>,low);
+ SET_DATA_INDEX(p1,idx1,dtype,x);
+ }
+ } else {
+ for (; i--;) {
+ x = m_add(<%=m_rand%>,low);
+ SET_DATA_STRIDE(p1,s1,dtype,x);
+ }
+ }
+}
+
+
+/*
+ Generate uniformly distributed random numbers on self narray.
+ @overload rand([[low],high])
+ @param [Numeric] low lower inclusive boundary of random numbers. (default=0)
+ @param [Numeric] high upper exclusive boundary of random numbers. (default=1 or 1+1i for complex types)
+ @return [Numo::<%=class_name%>] self.
+ @example
+ Numo::DFloat.new(6).rand
+ => Numo::DFloat#shape=[6]
+ [0.0617545, 0.373067, 0.794815, 0.201042, 0.116041, 0.344032]
+ Numo::DComplex.new(6).rand(5+5i)
+ => Numo::DComplex#shape=[6]
+ [2.69974+3.68908i, 0.825443+0.254414i, 0.540323+0.34354i, 4.52061+2.39322i, ...]
+ Numo::Int32.new(6).rand(2,5)
+ => Numo::Int32#shape=[6]
+ [4, 3, 3, 2, 4, 2]
+*/
+static VALUE
+<%=c_func(-1)%>(int argc, VALUE *args, VALUE self)
+{
+ rand_opt_t g;
+ VALUE v1=Qnil, v2=Qnil;
+ dtype high;
+ ndfunc_arg_in_t ain[1] = {{OVERWRITE,0}};
+ ndfunc_t ndf = {<%=c_iter%>, FULL_LOOP, 1,0, ain,0};
+
+ <% if is_int && !is_object %>
+ rb_scan_args(argc, args, "11", &v1, &v2);
+ if (v2==Qnil) {
+ g.low = m_zero;
+ g.max = high = m_num_to_data(v1);
+ <% else %>
+ rb_scan_args(argc, args, "02", &v1, &v2);
+ if (v2==Qnil) {
+ g.low = m_zero;
+ if (v1==Qnil) {
+ <% if is_complex %>
+ g.max = high = c_new(1,1);
+ <% else %>
+ g.max = high = m_one;
+ <% end %>
+ } else {
+ g.max = high = m_num_to_data(v1);
+ }
+ <% end %>
+ } else {
+ g.low = m_num_to_data(v1);
+ high = m_num_to_data(v2);
+ g.max = m_sub(high,g.low);
+ }
+ <% if is_int && !is_object %>
+ if (high <= g.low) {
+ rb_raise(rb_eArgError,"high must be larger than low");
+ }
+ <% end %>
+ na_ndloop3(&ndf, &g, 1, self);
+ return self;
+}
diff --git a/ext/numo/narray/gen/tmpl/rand_norm.c b/ext/numo/narray/gen/tmpl/rand_norm.c
new file mode 100644
index 0000000..da2431c
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/rand_norm.c
@@ -0,0 +1,119 @@
+typedef struct {
+ dtype mu;
+ rtype sigma;
+} randn_opt_t;
+
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ char *p1;
+ ssize_t s1;
+ size_t *idx1;
+ <% if is_complex %>
+ dtype *a0;
+ <% else %>
+ dtype *a0, *a1;
+ <% end %>
+ dtype mu;
+ rtype sigma;
+ randn_opt_t *g;
+
+ INIT_COUNTER(lp, i);
+ INIT_PTR_IDX(lp, 0, p1, s1, idx1);
+ g = (randn_opt_t*)(lp->opt_ptr);
+ mu = g->mu;
+ sigma = g->sigma;
+
+ if (idx1) {
+ <% if is_complex %>
+ for (; i--;) {
+ a0 = (dtype*)(p1+*idx1);
+ m_rand_norm(mu,sigma,a0);
+ idx1 += 1;
+ }
+ <% else %>
+ for (; i>1; i-=2) {
+ a0 = (dtype*)(p1+*idx1);
+ a1 = (dtype*)(p1+*(idx1+1));
+ m_rand_norm(mu,sigma,a0,a1);
+ idx1 += 2;
+ }
+ if (i>0) {
+ a0 = (dtype*)(p1+*idx1);
+ m_rand_norm(mu,sigma,a0,0);
+ }
+ <% end %>
+ } else {
+ <% if is_complex %>
+ for (; i--;) {
+ a0 = (dtype*)(p1);
+ m_rand_norm(mu,sigma,a0);
+ p1 += s1;
+ }
+ <% else %>
+ for (; i>1; i-=2) {
+ a0 = (dtype*)(p1);
+ a1 = (dtype*)(p1+s1);
+ m_rand_norm(mu,sigma,a0,a1);
+ p1 += s1*2;
+ }
+ if (i>0) {
+ a0 = (dtype*)(p1);
+ m_rand_norm(mu,sigma,a0,0);
+ }
+ <% end %>
+ }
+}
+
+/*
+ Generates random numbers from the normal distribution on self narray
+ using Box-Muller Transformation.
+ @overload rand_norm([mu,[sigma]])
+ @param [Numeric] mu mean of normal distribution. (default=0)
+ @param [Numeric] sigma standard deviation of normal distribution. (default=1)
+ @return [Numo::<%=class_name%>] self.
+ @example
+ Numo::DFloat.new(5,5).rand_norm
+ => Numo::DFloat#shape=[5,5]
+ [[-0.581255, -0.168354, 0.586895, -0.595142, -0.802802],
+ [-0.326106, 0.282922, 1.68427, 0.918499, -0.0485384],
+ [-0.464453, -0.992194, 0.413794, -0.60717, -0.699695],
+ [-1.64168, 0.48676, -0.875871, -1.43275, 0.812172],
+ [-0.209975, -0.103612, -0.878617, -1.42495, 1.0968]]
+ Numo::DFloat.new(5,5).rand_norm(10,0.1)
+ => Numo::DFloat#shape=[5,5]
+ [[9.9019, 9.90339, 10.0826, 9.98384, 9.72861],
+ [9.81507, 10.0272, 9.91445, 10.0568, 9.88923],
+ [10.0234, 9.97874, 9.96011, 9.9006, 9.99964],
+ [10.0186, 9.94598, 9.92236, 9.99811, 9.97003],
+ [9.79266, 9.95044, 9.95212, 9.93692, 10.2027]]
+ Numo::DComplex.new(3,3).rand_norm(5+5i)
+ => Numo::DComplex#shape=[3,3]
+ [[5.84303+4.40052i, 4.00984+6.08982i, 5.10979+5.13215i],
+ [4.26477+3.99655i, 4.90052+5.00763i, 4.46607+2.3444i],
+ [4.5528+7.11003i, 5.62117+6.69094i, 5.05443+5.35133i]]
+*/
+static VALUE
+<%=c_func(-1)%>(int argc, VALUE *args, VALUE self)
+{
+ int n;
+ randn_opt_t g;
+ VALUE v1=Qnil, v2=Qnil;
+ ndfunc_arg_in_t ain[1] = {{OVERWRITE,0}};
+ ndfunc_t ndf = {<%=c_iter%>, FULL_LOOP, 1,0, ain,0};
+
+ n = rb_scan_args(argc, args, "02", &v1, &v2);
+ if (n == 0) {
+ g.mu = m_zero;
+ } else {
+ g.mu = m_num_to_data(v1);
+ }
+ if (n == 2) {
+ g.sigma = NUM2DBL(v2);
+ } else {
+ g.sigma = 1;
+ }
+ na_ndloop3(&ndf, &g, 1, self);
+ return self;
+}
diff --git a/ext/numo/narray/gen/tmpl/seq.c b/ext/numo/narray/gen/tmpl/seq.c
new file mode 100644
index 0000000..300c321
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/seq.c
@@ -0,0 +1,92 @@
+<% if is_int && !is_object %>
+typedef double seq_data_t;
+<% else %>
+typedef dtype seq_data_t;
+<% end %>
+
+<% if is_object %>
+typedef size_t seq_count_t;
+<% else %>
+typedef double seq_count_t;
+<% end %>
+
+typedef struct {
+ seq_data_t beg;
+ seq_data_t step;
+ seq_count_t count;
+} seq_opt_t;
+
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ char *p1;
+ ssize_t s1;
+ size_t *idx1;
+ dtype x;
+ seq_data_t beg, step;
+ seq_count_t c;
+ seq_opt_t *g;
+
+ INIT_COUNTER(lp, i);
+ INIT_PTR_IDX(lp, 0, p1, s1, idx1);
+ g = (seq_opt_t*)(lp->opt_ptr);
+ beg = g->beg;
+ step = g->step;
+ c = g->count;
+ if (idx1) {
+ for (; i--;) {
+ x = f_seq(beg,step,c++);
+ *(dtype*)(p1+*idx1) = x;
+ idx1++;
+ }
+ } else {
+ for (; i--;) {
+ x = f_seq(beg,step,c++);
+ *(dtype*)(p1) = x;
+ p1 += s1;
+ }
+ }
+ g->count = c;
+}
+
+/*
+ Set linear sequence of numbers to self. The sequence is obtained from
+ beg+i*step
+ where i is 1-dimensional index.
+ @overload seq([beg,[step]])
+ @param [Numeric] beg begining of sequence. (default=0)
+ @param [Numeric] step step of sequence. (default=1)
+ @return [Numo::<%=class_name%>] self.
+ @example
+ Numo::DFloat.new(6).seq(1,-0.2)
+ => Numo::DFloat#shape=[6]
+ [1, 0.8, 0.6, 0.4, 0.2, 0]
+ Numo::DComplex.new(6).seq(1,-0.2+0.2i)
+ => Numo::DComplex#shape=[6]
+ [1+0i, 0.8+0.2i, 0.6+0.4i, 0.4+0.6i, 0.2+0.8i, 0+1i]
+*/
+static VALUE
+<%=c_func(-1)%>(int argc, VALUE *args, VALUE self)
+{
+ seq_opt_t *g;
+ VALUE vbeg=Qnil, vstep=Qnil;
+ ndfunc_arg_in_t ain[1] = {{OVERWRITE,0}};
+ ndfunc_t ndf = {<%=c_iter%>, FULL_LOOP, 1,0, ain,0};
+
+ g = ALLOCA_N(seq_opt_t,1);
+ g->beg = m_zero;
+ g->step = m_one;
+ g->count = 0;
+ rb_scan_args(argc, args, "02", &vbeg, &vstep);
+<% if is_int && !is_object %>
+ if (vbeg!=Qnil) {g->beg = NUM2DBL(vbeg);}
+ if (vstep!=Qnil) {g->step = NUM2DBL(vstep);}
+<% else %>
+ if (vbeg!=Qnil) {g->beg = m_num_to_data(vbeg);}
+ if (vstep!=Qnil) {g->step = m_num_to_data(vstep);}
+<% end %>
+
+ na_ndloop3(&ndf, g, 1, self);
+ return self;
+}
diff --git a/ext/numo/narray/gen/tmpl/set2.c b/ext/numo/narray/gen/tmpl/set2.c
new file mode 100644
index 0000000..2240979
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/set2.c
@@ -0,0 +1,56 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ char *p1, *p2;
+ ssize_t s1, s2;
+ size_t *idx1, *idx2;
+ dtype x;
+ <%=dtype%> y;
+ INIT_COUNTER(lp, i);
+ INIT_PTR_IDX(lp, 0, p1, s1, idx1);
+ INIT_PTR_IDX(lp, 1, p2, s2, idx2);
+ if (idx1) {
+ if (idx2) {
+ for (; i--;) {
+ GET_DATA(p1+*idx1,dtype,x);
+ GET_DATA_INDEX(p2,idx2,<%=dtype%>,y);
+ x = m_<%=name%>(x,y);
+ SET_DATA_INDEX(p1,idx1,dtype,x);
+ }
+ } else {
+ for (; i--;) {
+ GET_DATA(p1+*idx1,dtype,x);
+ GET_DATA_STRIDE(p2,s2,<%=dtype%>,y);
+ x = m_<%=name%>(x,y);
+ SET_DATA_INDEX(p1,idx1,dtype,x);
+ }
+ }
+ } else {
+ if (idx2) {
+ for (; i--;) {
+ GET_DATA(p1,dtype,x);
+ GET_DATA_INDEX(p2,idx2,<%=dtype%>,y);
+ x = m_<%=name%>(x,y);
+ SET_DATA_STRIDE(p1,s1,dtype,x);
+ }
+ } else {
+ for (; i--;) {
+ GET_DATA(p1,dtype,x);
+ GET_DATA_STRIDE(p2,s2,<%=dtype%>,y);
+ x = m_<%=name%>(x,y);
+ SET_DATA_STRIDE(p1,s1,dtype,x);
+ }
+ }
+ }
+}
+
+static VALUE
+<%=c_func(1)%>(VALUE self, VALUE a1)
+{
+ ndfunc_arg_in_t ain[2] = {{OVERWRITE,0},{<%=result_class%>,0}};
+ ndfunc_t ndf = { <%=c_iter%>, FULL_LOOP, 2, 0, ain, 0 };
+
+ na_ndloop(&ndf, 2, self, a1);
+ return a1;
+}
diff --git a/ext/numo/narray/gen/tmpl/sort.c b/ext/numo/narray/gen/tmpl/sort.c
new file mode 100644
index 0000000..b9f580c
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/sort.c
@@ -0,0 +1,47 @@
+<% (is_float ? ["_ignan","_prnan"] : [""]).each do |j| %>
+static void
+<%=c_iter%><%=j%>(na_loop_t *const lp)
+{
+ size_t n;
+ char *ptr;
+ ssize_t step;
+
+ INIT_COUNTER(lp, n);
+ INIT_PTR(lp, 0, ptr, step);
+ <%=type_name%>_qsort<%=j%>(ptr, n, step);
+}
+<% end %>
+
+/*
+ <%=name%> of self.
+<% if is_float %>
+ @overload <%=name%>(axis:nil, nan:false)
+ @param [TrueClass] nan If true, propagete NaN. If false, ignore NaN.
+<% else %>
+ @overload <%=name%>(axis:nil)
+<% end %>
+ @param [Numeric,Array,Range] axis Affected dimensions.
+ @return [Numo::<%=class_name%>] returns result of <%=name%>.
+ @example
+ Numo::DFloat[3,4,1,2].sort => Numo::DFloat[1,2,3,4]
+*/
+static VALUE
+<%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
+{
+ VALUE reduce;
+ ndfunc_arg_in_t ain[2] = {{OVERWRITE,0},{sym_reduce,0}};
+ ndfunc_t ndf = {0, STRIDE_LOOP|NDF_FLAT_REDUCE, 2,0, ain,0};
+
+ if (!TEST_INPLACE(self)) {
+ self = na_copy(self);
+ }
+ <% if is_float %>
+ ndf.func = <%=c_iter%>_ignan;
+ reduce = na_reduce_dimension(argc, argv, 1, &self, &ndf, <%=c_iter%>_prnan);
+ <% else %>
+ ndf.func = <%=c_iter%>;
+ reduce = na_reduce_dimension(argc, argv, 1, &self, &ndf, 0);
+ <% end %>
+ na_ndloop(&ndf, 2, self, reduce);
+ return self;
+}
diff --git a/ext/numo/narray/gen/tmpl/sort_index.c b/ext/numo/narray/gen/tmpl/sort_index.c
new file mode 100644
index 0000000..39dc160
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/sort_index.c
@@ -0,0 +1,102 @@
+<% (is_float ? ["_ignan","_prnan"] : [""]).each do |j|
+ [64,32].each do |i| %>
+#define idx_t int<%=i%>_t
+static void
+<%=type_name%>_index<%=i%>_qsort<%=j%>(na_loop_t *const lp)
+{
+ size_t i, n, idx;
+ char *d_ptr, *i_ptr, *o_ptr;
+ ssize_t d_step, i_step, o_step;
+ char **ptr;
+
+ INIT_COUNTER(lp, n);
+ INIT_PTR(lp, 0, d_ptr, d_step);
+ INIT_PTR(lp, 1, i_ptr, i_step);
+ INIT_PTR(lp, 2, o_ptr, o_step);
+
+ ptr = (char**)(lp->opt_ptr);
+
+ //printf("(ptr=%lx, d_ptr=%lx,d_step=%ld, i_ptr=%lx,i_step=%ld, o_ptr=%lx,o_step=%ld)\n",(size_t)ptr,(size_t)d_ptr,(ssize_t)d_step,(size_t)i_ptr,(ssize_t)i_step,(size_t)o_ptr,(ssize_t)o_step);
+
+ for (i=0; i<n; i++) {
+ ptr[i] = d_ptr + d_step * i;
+ //printf("(%ld,%.3f)",i,*(double*)ptr[i]);
+ }
+
+ <%=type_name%>_index_qsort<%=j%>(ptr, n, sizeof(dtype*));
+
+ //d_ptr = lp->args[0].ptr;
+ //printf("(d_ptr=%lx)\n",(size_t)d_ptr);
+
+ for (i=0; i<n; i++) {
+ idx = (ptr[i] - d_ptr) / d_step;
+ *(idx_t*)o_ptr = *(idx_t*)(i_ptr + i_step * idx);
+ //printf("(idx[%ld]=%ld,%d)",i,idx,*(idx_t*)o_ptr);
+ o_ptr += o_step;
+ }
+ //printf("\n");
+}
+#undef idx_t
+<% end;end %>
+
+/*
+ <%=name%>. Returns an index array of sort result.
+<% if is_float %>
+ @overload <%=name%>(axis:nil, nan:false)
+ @param [TrueClass] nan If true, propagete NaN. If false, ignore NaN.
+<% else %>
+ @overload <%=name%>(axis:nil)
+<% end %>
+ @param [Numeric,Array,Range] axis Affected dimensions.
+ @return [Integer,Numo::Int] returns result index of <%=name%>.
+ @example
+ Numo::NArray[3,4,1,2].sort_index => Numo::Int32[2,3,0,1]
+*/
+static VALUE
+<%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
+{
+ size_t size;
+ narray_t *na;
+ VALUE idx, tmp, reduce, res;
+ char *buf;
+ ndfunc_arg_in_t ain[3] = {{cT,0},{0,0},{sym_reduce,0}};
+ ndfunc_arg_out_t aout[1] = {{0,0,0}};
+ ndfunc_t ndf = {0, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_CUM, 3,1, ain,aout};
+
+ GetNArray(self,na);
+ if (na->ndim==0) {
+ return INT2FIX(0);
+ }
+ if (na->size > (~(u_int32_t)0)) {
+ ain[1].type =
+ aout[0].type = numo_cInt64;
+ idx = nary_new(numo_cInt64, na->ndim, na->shape);
+ <% if is_float %>
+ ndf.func = <%=type_name%>_index64_qsort_ignan;
+ reduce = na_reduce_dimension(argc, argv, 1, &self, &ndf,
+ <%=type_name%>_index64_qsort_prnan);
+ <% else %>
+ ndf.func = <%=type_name%>_index64_qsort;
+ reduce = na_reduce_dimension(argc, argv, 1, &self, &ndf, 0);
+ <% end %>
+ } else {
+ ain[1].type =
+ aout[0].type = numo_cInt32;
+ idx = nary_new(numo_cInt32, na->ndim, na->shape);
+ <% if is_float %>
+ ndf.func = <%=type_name%>_index32_qsort_ignan;
+ reduce = na_reduce_dimension(argc, argv, 1, &self, &ndf,
+ <%=type_name%>_index32_qsort_prnan);
+ <% else %>
+ ndf.func = <%=type_name%>_index32_qsort;
+ reduce = na_reduce_dimension(argc, argv, 1, &self, &ndf, 0);
+ <% end %>
+ }
+ rb_funcall(idx, rb_intern("seq"), 0);
+
+ size = na->size*sizeof(void*);
+ buf = rb_alloc_tmp_buffer(&tmp, size);
+ res = na_ndloop3(&ndf, buf, 3, self, idx, reduce);
+ rb_free_tmp_buffer(&tmp);
+ return res;
+}
diff --git a/ext/numo/narray/gen/tmpl/store.c b/ext/numo/narray/gen/tmpl/store.c
new file mode 100644
index 0000000..1cdda16
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/store.c
@@ -0,0 +1,41 @@
+<% children.each do |c|%>
+<%= c.result %>
+
+<% end %>
+/*
+ Store elements to Numo::<%=class_name%> from other.
+ @overload store(other)
+ @param [Object] other
+ @return [Numo::<%=class_name%>] self
+*/
+static VALUE
+<%=c_func(1)%>(VALUE self, VALUE obj)
+{
+ VALUE r, klass;
+
+ klass = CLASS_OF(obj);
+
+ <% definitions.each do |x| %>
+ if (<%=x.condition("klass")%>) {
+ <%=x.c_func%>(self,obj);
+ return self;
+ }
+ <% end %>
+
+ if (IsNArray(obj)) {
+ r = rb_funcall(obj, rb_intern("coerce_cast"), 1, cT);
+ if (CLASS_OF(r)==cT) {
+ <%=c_func%>(self,r);
+ return self;
+ }
+ }
+
+ <% if is_object %>
+ robject_store_numeric(self,obj);
+ <% else %>
+ rb_raise(nary_eCastError, "unknown conversion from %s to %s",
+ rb_class2name(CLASS_OF(obj)),
+ rb_class2name(CLASS_OF(self)));
+ <% end %>
+ return self;
+}
diff --git a/ext/numo/narray/gen/tmpl/store_array.c b/ext/numo/narray/gen/tmpl/store_array.c
new file mode 100644
index 0000000..40cb3b5
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/store_array.c
@@ -0,0 +1,102 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i, n;
+ size_t i1, n1;
+ VALUE v1, *ptr;
+ char *p1;
+ size_t s1, *idx1;
+ VALUE x;
+ double y;
+ dtype z;
+ size_t len, c;
+ double beg, step;
+
+ INIT_COUNTER(lp, n);
+ INIT_PTR_IDX(lp, 0, p1, s1, idx1);
+ v1 = lp->args[1].value;
+ i = 0;
+
+ if (lp->args[1].ptr) {
+ if (v1 == Qtrue) {
+ iter_<%=type_name%>_store_<%=type_name%>(lp);
+ i = lp->args[1].shape[0];
+ if (idx1) {
+ idx1 += i;
+ } else {
+ p1 += s1 * i;
+ }
+ }
+ goto loop_end;
+ }
+
+ ptr = &v1;
+
+ switch(TYPE(v1)) {
+ case T_ARRAY:
+ n1 = RARRAY_LEN(v1);
+ ptr = RARRAY_PTR(v1);
+ break;
+ case T_NIL:
+ n1 = 0;
+ break;
+ default:
+ n1 = 1;
+ }
+
+ if (idx1) {
+ for (i=i1=0; i1<n1 && i<n; i++,i1++) {
+ x = ptr[i1];
+ if (rb_obj_is_kind_of(x, rb_cRange) || rb_obj_is_kind_of(x, na_cStep)) {
+ nary_step_sequence(x,&len,&beg,&step);
+ for (c=0; c<len && i<n; c++,i++) {
+ y = beg + step * c;
+ z = m_from_double(y);
+ SET_DATA_INDEX(p1, idx1, dtype, z);
+ }
+ }
+ else if (TYPE(x) != T_ARRAY) {
+ z = m_num_to_data(x);
+ SET_DATA_INDEX(p1, idx1, dtype, z);
+ }
+ }
+ } else {
+ for (i=i1=0; i1<n1 && i<n; i++,i1++) {
+ x = ptr[i1];
+ if (rb_obj_is_kind_of(x, rb_cRange) || rb_obj_is_kind_of(x, na_cStep)) {
+ nary_step_sequence(x,&len,&beg,&step);
+ for (c=0; c<len && i<n; c++,i++) {
+ y = beg + step * c;
+ z = m_from_double(y);
+ SET_DATA_STRIDE(p1, s1, dtype, z);
+ }
+ }
+ else if (TYPE(x) != T_ARRAY) {
+ z = m_num_to_data(x);
+ SET_DATA_STRIDE(p1, s1, dtype, z);
+ }
+ }
+ }
+
+ loop_end:
+ z = m_zero;
+ if (idx1) {
+ for (; i<n; i++) {
+ SET_DATA_INDEX(p1, idx1, dtype, z);
+ }
+ } else {
+ for (; i<n; i++) {
+ SET_DATA_STRIDE(p1, s1, dtype, z);
+ }
+ }
+}
+
+static VALUE
+<%=c_func%>(VALUE self, VALUE rary)
+{
+ ndfunc_arg_in_t ain[2] = {{OVERWRITE,0},{rb_cArray,0}};
+ ndfunc_t ndf = {<%=c_iter%>, FULL_LOOP, 2, 0, ain, 0};
+
+ na_ndloop_store_rarray(&ndf, self, rary);
+ return self;
+}
diff --git a/ext/numo/narray/gen/tmpl/store_bit.c b/ext/numo/narray/gen/tmpl/store_bit.c
new file mode 100644
index 0000000..2422497
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/store_bit.c
@@ -0,0 +1,55 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ char *p1;
+ size_t p2;
+ ssize_t s1, s2;
+ size_t *idx1, *idx2;
+ BIT_DIGIT *a2, x;
+ dtype y;
+
+ INIT_COUNTER(lp, i);
+ INIT_PTR_IDX(lp, 0, p1, s1, idx1);
+ INIT_PTR_BIT_IDX(lp, 1, a2, p2, s2, idx2);
+ if (idx2) {
+ if (idx1) {
+ for (; i--;) {
+ LOAD_BIT(a2, p2+*idx2, x); idx2++;
+ y = m_from_real(x);
+ SET_DATA_INDEX(p1,idx1,dtype,y);
+ }
+ } else {
+ for (; i--;) {
+ LOAD_BIT(a2, p2+*idx2, x); idx2++;
+ y = m_from_real(x);
+ SET_DATA_STRIDE(p1,s1,dtype,y);
+ }
+ }
+ } else {
+ if (idx1) {
+ for (; i--;) {
+ LOAD_BIT(a2, p2, x); p2 += s2;
+ y = m_from_real(x);
+ SET_DATA_INDEX(p1,idx1,dtype,y);
+ }
+ } else {
+ for (; i--;) {
+ LOAD_BIT(a2, p2, x); p2 += s2;
+ y = m_from_real(x);
+ SET_DATA_STRIDE(p1,s1,dtype,y);
+ }
+ }
+ }
+}
+
+
+static VALUE
+<%=c_func(:nodef)%>(VALUE self, VALUE obj)
+{
+ ndfunc_arg_in_t ain[2] = {{OVERWRITE,0},{Qnil,0}};
+ ndfunc_t ndf = {<%=c_iter%>, FULL_LOOP, 2,0, ain,0};
+
+ na_ndloop(&ndf, 2, self, obj);
+ return self;
+}
diff --git a/ext/numo/narray/gen/tmpl/store_from.c b/ext/numo/narray/gen/tmpl/store_from.c
new file mode 100644
index 0000000..bdbef70
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/store_from.c
@@ -0,0 +1,53 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i, s1, s2;
+ char *p1, *p2;
+ size_t *idx1, *idx2;
+ <%=dtype%> x;
+ dtype y;
+
+ INIT_COUNTER(lp, i);
+ INIT_PTR_IDX(lp, 0, p1, s1, idx1);
+ INIT_PTR_IDX(lp, 1, p2, s2, idx2);
+ if (idx2) {
+ if (idx1) {
+ for (; i--;) {
+ GET_DATA_INDEX(p2,idx2,<%=dtype%>,x);
+ y = <%=macro%>(x);
+ SET_DATA_INDEX(p1,idx1,dtype,y);
+ }
+ } else {
+ for (; i--;) {
+ GET_DATA_INDEX(p2,idx2,<%=dtype%>,x);
+ y = <%=macro%>(x);
+ SET_DATA_STRIDE(p1,s1,dtype,y);
+ }
+ }
+ } else {
+ if (idx1) {
+ for (; i--;) {
+ GET_DATA_STRIDE(p2,s2,<%=dtype%>,x);
+ y = <%=macro%>(x);
+ SET_DATA_INDEX(p1,idx1,dtype,y);
+ }
+ } else {
+ for (; i--;) {
+ GET_DATA_STRIDE(p2,s2,<%=dtype%>,x);
+ y = <%=macro%>(x);
+ SET_DATA_STRIDE(p1,s1,dtype,y);
+ }
+ }
+ }
+}
+
+
+static VALUE
+<%=c_func(:nodef)%>(VALUE self, VALUE obj)
+{
+ ndfunc_arg_in_t ain[2] = {{OVERWRITE,0},{Qnil,0}};
+ ndfunc_t ndf = { <%=c_iter%>, FULL_LOOP, 2, 0, ain, 0 };
+
+ na_ndloop(&ndf, 2, self, obj);
+ return self;
+}
diff --git a/ext/numo/narray/gen/tmpl/store_numeric.c b/ext/numo/narray/gen/tmpl/store_numeric.c
new file mode 100644
index 0000000..5f770c3
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/store_numeric.c
@@ -0,0 +1,9 @@
+static VALUE
+<%=c_func(:nodef)%>(VALUE self, VALUE obj)
+{
+ dtype x;
+ x = m_num_to_data(obj);
+ obj = <%=type_name%>_new_dim0(x);
+ <%=parent.c_func%>(self,obj);
+ return self;
+}
diff --git a/ext/numo/narray/gen/tmpl/to_a.c b/ext/numo/narray/gen/tmpl/to_a.c
new file mode 100644
index 0000000..6032a6b
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/to_a.c
@@ -0,0 +1,41 @@
+void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i, s1;
+ char *p1;
+ size_t *idx1;
+ dtype x;
+ volatile VALUE a, y;
+
+ INIT_COUNTER(lp, i);
+ INIT_PTR_IDX(lp, 0, p1, s1, idx1);
+ a = rb_ary_new2(i);
+ rb_ary_push(lp->args[1].value, a);
+ if (idx1) {
+ for (; i--;) {
+ GET_DATA_INDEX(p1,idx1,dtype,x);
+ y = m_data_to_num(x);
+ rb_ary_push(a,y);
+ }
+ } else {
+ for (; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ y = m_data_to_num(x);
+ rb_ary_push(a,y);
+ }
+ }
+}
+
+/*
+ Convert self to Array.
+ @overload <%=name%>
+ @return [Array]
+*/
+static VALUE
+<%=c_func(0)%>(VALUE self)
+{
+ ndfunc_arg_in_t ain[3] = {{Qnil,0},{sym_loop_opt},{sym_option}};
+ ndfunc_arg_out_t aout[1] = {{rb_cArray,0}}; // dummy?
+ ndfunc_t ndf = { <%=c_iter%>, FULL_LOOP_NIP, 3, 1, ain, aout };
+ return na_ndloop_cast_narray_to_rarray(&ndf, self, Qnil);
+}
diff --git a/ext/numo/narray/gen/tmpl/unary.c b/ext/numo/narray/gen/tmpl/unary.c
new file mode 100644
index 0000000..382c638
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/unary.c
@@ -0,0 +1,58 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ char *p1, *p2;
+ ssize_t s1, s2;
+ size_t *idx1, *idx2;
+ dtype x;
+
+ INIT_COUNTER(lp, i);
+ INIT_PTR_IDX(lp, 0, p1, s1, idx1);
+ INIT_PTR_IDX(lp, 1, p2, s2, idx2);
+
+ if (idx1) {
+ if (idx2) {
+ for (; i--;) {
+ GET_DATA_INDEX(p1,idx1,dtype,x);
+ x = m_<%=name%>(x);
+ SET_DATA_INDEX(p2,idx2,dtype,x);
+ }
+ } else {
+ for (; i--;) {
+ GET_DATA_INDEX(p1,idx1,dtype,x);
+ x = m_<%=name%>(x);
+ SET_DATA_STRIDE(p2,s2,dtype,x);
+ }
+ }
+ } else {
+ if (idx2) {
+ for (; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ x = m_<%=name%>(x);
+ SET_DATA_INDEX(p2,idx2,dtype,x);
+ }
+ } else {
+ for (; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ x = m_<%=name%>(x);
+ SET_DATA_STRIDE(p2,s2,dtype,x);
+ }
+ }
+ }
+}
+
+/*
+ Unary <%=name%>.
+ @overload <%=op_map%>
+ @return [Numo::<%=class_name%>] <%=name%> of self.
+*/
+static VALUE
+<%=c_func(0)%>(VALUE self)
+{
+ ndfunc_arg_in_t ain[1] = {{cT,0}};
+ ndfunc_arg_out_t aout[1] = {{cT,0}};
+ ndfunc_t ndf = {<%=c_iter%>, FULL_LOOP, 1,1, ain,aout};
+
+ return na_ndloop(&ndf, 1, self);
+}
diff --git a/ext/numo/narray/gen/tmpl/unary2.c b/ext/numo/narray/gen/tmpl/unary2.c
new file mode 100644
index 0000000..58c239a
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/unary2.c
@@ -0,0 +1,58 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ char *p1, *p2;
+ ssize_t s1, s2;
+ size_t *idx1, *idx2;
+ dtype x;
+ <%=dtype%> y;
+ INIT_COUNTER(lp, i);
+ INIT_PTR_IDX(lp, 0, p1, s1, idx1);
+ INIT_PTR_IDX(lp, 1, p2, s2, idx2);
+ if (idx1) {
+ if (idx2) {
+ for (; i--;) {
+ GET_DATA_INDEX(p1,idx1,dtype,x);
+ y = m_<%=name%>(x);
+ SET_DATA_INDEX(p2,idx2,<%=dtype%>,y);
+ }
+ } else {
+ for (; i--;) {
+ GET_DATA_INDEX(p1,idx1,dtype,x);
+ y = m_<%=name%>(x);
+ SET_DATA_STRIDE(p2,s2,<%=dtype%>,y);
+ }
+ }
+ } else {
+ if (idx2) {
+ for (; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ y = m_<%=name%>(x);
+ SET_DATA_INDEX(p2,idx2,<%=dtype%>,y);
+ }
+ } else {
+ for (; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ y = m_<%=name%>(x);
+ SET_DATA_STRIDE(p2,s2,<%=dtype%>,y);
+ }
+ }
+ }
+}
+
+
+/*
+ <%=name%> of self.
+ @overload <%=name%>
+ @return [Numo::<%=real_class_name%>] <%=name%> of self.
+*/
+static VALUE
+<%=c_func(0)%>(VALUE self)
+{
+ ndfunc_arg_in_t ain[1] = {{cT,0}};
+ ndfunc_arg_out_t aout[1] = {{<%=result_class%>,0}};
+ ndfunc_t ndf = { <%=c_iter%>, FULL_LOOP, 1, 1, ain, aout };
+
+ return na_ndloop(&ndf, 1, self);
+}
diff --git a/ext/numo/narray/gen/tmpl/unary_ret2.c b/ext/numo/narray/gen/tmpl/unary_ret2.c
new file mode 100644
index 0000000..feba990
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/unary_ret2.c
@@ -0,0 +1,33 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ char *p1, *p2, *p3;
+ ssize_t s1, s2, s3;
+ dtype x, y, z;
+ INIT_COUNTER(lp, i);
+ INIT_PTR(lp, 0, p1, s1);
+ INIT_PTR(lp, 1, p2, s2);
+ INIT_PTR(lp, 2, p3, s3);
+ for (; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ m_<%=name%>(x,y,z);
+ SET_DATA_STRIDE(p2,s2,dtype,y);
+ SET_DATA_STRIDE(p3,s3,dtype,z);
+ }
+}
+
+/*
+ <%=name%> of self.
+ @overload <%=name%>
+ @return [Numo::<%=real_class_name%>] <%=name%> of self.
+*/
+static VALUE
+<%=c_func(0)%>(VALUE self)
+{
+ ndfunc_arg_in_t ain[1] = {{cT,0}};
+ ndfunc_arg_out_t aout[2] = {{cT,0},{cT,0}};
+ ndfunc_t ndf = {<%=c_iter%>, STRIDE_LOOP, 1,2, ain,aout};
+
+ return na_ndloop(&ndf, 1, self);
+}
diff --git a/ext/numo/narray/gen/tmpl/unary_s.c b/ext/numo/narray/gen/tmpl/unary_s.c
new file mode 100644
index 0000000..6ec8707
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl/unary_s.c
@@ -0,0 +1,57 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ char *p1, *p2;
+ ssize_t s1, s2;
+ size_t *idx1, *idx2;
+ dtype x;
+ INIT_COUNTER(lp, i);
+ INIT_PTR_IDX(lp, 0, p1, s1, idx1);
+ INIT_PTR_IDX(lp, 1, p2, s2, idx2);
+ if (idx1) {
+ if (idx2) {
+ for (; i--;) {
+ GET_DATA_INDEX(p1,idx1,dtype,x);
+ x = m_<%=name%>(x);
+ SET_DATA_INDEX(p2,idx2,dtype,x);
+ }
+ } else {
+ for (; i--;) {
+ GET_DATA_INDEX(p1,idx1,dtype,x);
+ x = m_<%=name%>(x);
+ SET_DATA_STRIDE(p2,s2,dtype,x);
+ }
+ }
+ } else {
+ if (idx2) {
+ for (; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ x = m_<%=name%>(x);
+ SET_DATA_INDEX(p2,idx2,dtype,x);
+ }
+ } else {
+ for (; i--;) {
+ GET_DATA_STRIDE(p1,s1,dtype,x);
+ x = m_<%=name%>(x);
+ SET_DATA_STRIDE(p2,s2,dtype,x);
+ }
+ }
+ }
+}
+
+/*
+ Calculate <%=name%>(x).
+ @overload <%=name%>(x)
+ @param [Numo::NArray,Numeric] x input value
+ @return [Numo::<%=class_name%>] result of <%=name%>(x).
+*/
+static VALUE
+<%=c_func(1)%>(VALUE mod, VALUE a1)
+{
+ ndfunc_arg_in_t ain[1] = {{cT,0}};
+ ndfunc_arg_out_t aout[1] = {{cT,0}};
+ ndfunc_t ndf = { <%=c_iter%>, FULL_LOOP, 1, 1, ain, aout };
+
+ return na_ndloop(&ndf, 1, a1);
+}
diff --git a/ext/numo/narray/gen/tmpl_bit/allocate.c b/ext/numo/narray/gen/tmpl_bit/allocate.c
new file mode 100644
index 0000000..8759328
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl_bit/allocate.c
@@ -0,0 +1,24 @@
+static VALUE
+<%=c_func(0)%>(VALUE self)
+{
+ narray_t *na;
+ char *ptr;
+
+ GetNArray(self,na);
+
+ switch(NA_TYPE(na)) {
+ case NARRAY_DATA_T:
+ ptr = NA_DATA_PTR(na);
+ if (na->size > 0 && ptr == NULL) {
+ ptr = xmalloc(((na->size-1)/8/sizeof(BIT_DIGIT)+1)*sizeof(BIT_DIGIT));
+ NA_DATA_PTR(na) = ptr;
+ }
+ break;
+ case NARRAY_VIEW_T:
+ rb_funcall(NA_VIEW_DATA(na), rb_intern("allocate"), 0);
+ break;
+ default:
+ rb_raise(rb_eRuntimeError,"invalid narray type");
+ }
+ return self;
+}
diff --git a/ext/numo/narray/gen/tmpl_bit/aref.c b/ext/numo/narray/gen/tmpl_bit/aref.c
new file mode 100644
index 0000000..adb1d93
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl_bit/aref.c
@@ -0,0 +1,55 @@
+/*
+ Array element referenece or slice view.
+ @overload [](dim0,...,dimL)
+ @param [Numeric,Range,etc] dim0,...,dimL Multi-dimensional Index.
+ @return [Numeric,NArray::<%=class_name%>] Element object or NArray view.
+
+ --- Returns the element at +dim0+, +dim1+, ... are Numeric indices
+ for each dimension, or returns a NArray View as a sliced subarray if
+ +dim0+, +dim1+, ... includes other than Numeric index, e.g., Range
+ or Array or true.
+
+ @example
+ a = Numo::DFloat.new(4,5).seq
+ => Numo::DFloat#shape=[4,5]
+ [[0, 1, 2, 3, 4],
+ [5, 6, 7, 8, 9],
+ [10, 11, 12, 13, 14],
+ [15, 16, 17, 18, 19]]
+
+ a[1,1]
+ => 6.0
+
+ a[1..3,1]
+ => Numo::DFloat#shape=[3]
+ [6, 11, 16]
+
+ a[1,[1,3,4]]
+ => Numo::DFloat#shape=[3]
+ [6, 8, 9]
+
+ a[true,2].fill(99)
+ a
+ => Numo::DFloat#shape=[4,5]
+ [[0, 1, 99, 3, 4],
+ [5, 6, 99, 8, 9],
+ [10, 11, 99, 13, 14],
+ [15, 16, 99, 18, 19]]
+ */
+static VALUE
+<%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
+{
+ int nd;
+ size_t pos;
+ char *ptr;
+ dtype x;
+
+ nd = na_get_result_dimension(self, argc, argv, 1, &pos);
+ if (nd) {
+ return na_aref_main(argc, argv, self, 0, nd);
+ } else {
+ ptr = na_get_pointer_for_read(self);
+ LOAD_BIT(ptr,pos,x);
+ return m_data_to_num(x);
+ }
+}
diff --git a/ext/numo/narray/gen/tmpl_bit/aset.c b/ext/numo/narray/gen/tmpl_bit/aset.c
new file mode 100644
index 0000000..9b33c5c
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl_bit/aset.c
@@ -0,0 +1,65 @@
+/*
+ Array element(s) set.
+ @overload []=(dim0,..,dimL,val)
+ @param [Numeric,Range,etc] dim0,..,dimL Multi-dimensional Index.
+ @param [Numeric,Numo::NArray,etc] val Value(s) to be set to self.
+ @return [Numeric] returns val (last argument).
+
+ --- Replace element(s) at +dim0+, +dim1+, ... (index/range/array/true
+ for each dimention). Broadcasting mechanism is applied.
+
+ @example
+ a = Numo::DFloat.new(3,4).seq
+ => Numo::DFloat#shape=[3,4]
+ [[0, 1, 2, 3],
+ [4, 5, 6, 7],
+ [8, 9, 10, 11]]
+
+ a[1,2]=99
+ a
+ => Numo::DFloat#shape=[3,4]
+ [[0, 1, 2, 3],
+ [4, 5, 99, 7],
+ [8, 9, 10, 11]]
+
+ a[1,[0,2]] = [101,102]
+ a
+ => Numo::DFloat#shape=[3,4]
+ [[0, 1, 2, 3],
+ [101, 5, 102, 7],
+ [8, 9, 10, 11]]
+
+ a[1,true]=99
+ a
+ => Numo::DFloat#shape=[3,4]
+ [[0, 1, 2, 3],
+ [99, 99, 99, 99],
+ [8, 9, 10, 11]]
+
+*/
+static VALUE
+<%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
+{
+ int nd;
+ size_t pos;
+ char *ptr;
+ VALUE a;
+ dtype x;
+
+ argc--;
+ if (argc==0) {
+ <%=c_func.sub(/_aset/,"_store")%>(self, argv[argc]);
+ } else {
+ nd = na_get_result_dimension(self, argc, argv, 1, &pos);
+ if (nd) {
+ a = na_aref_main(argc, argv, self, 0, nd);
+ <%=c_func.sub(/_aset/,"_store")%>(a, argv[argc]);
+ } else {
+ x = <%=type_name%>_extract_data(argv[argc]);
+ ptr = na_get_pointer_for_read_write(self);
+ STORE_BIT(ptr,pos,x);
+ }
+
+ }
+ return argv[argc];
+}
diff --git a/ext/numo/narray/gen/tmpl_bit/binary.c b/ext/numo/narray/gen/tmpl_bit/binary.c
new file mode 100644
index 0000000..2eccc26
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl_bit/binary.c
@@ -0,0 +1,94 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t n;
+ size_t p1, p2, p3;
+ ssize_t s1, s2, s3;
+ size_t *idx1, *idx2, *idx3;
+ int o1, o2, l1, l2, r1, r2, len;
+ BIT_DIGIT *a1, *a2, *a3;
+ BIT_DIGIT x, y;
+
+ INIT_COUNTER(lp, n);
+ INIT_PTR_BIT_IDX(lp, 0, a1, p1, s1, idx1);
+ INIT_PTR_BIT_IDX(lp, 1, a2, p2, s2, idx2);
+ INIT_PTR_BIT_IDX(lp, 2, a3, p3, s3, idx3);
+ if (s1!=1 || s2!=1 || s3!=1 || idx1 || idx2 || idx3) {
+ for (; n--;) {
+ LOAD_BIT_STEP(a1, p1, s1, idx1, x);
+ LOAD_BIT_STEP(a2, p2, s2, idx2, y);
+ x = m_<%=name%>(x,y);
+ STORE_BIT_STEP(a3, p3, s3, idx3, x);
+ }
+ } else {
+ o1 = p1 % NB;
+ o1 -= p3;
+ o2 = p2 % NB;
+ o2 -= p3;
+ l1 = NB+o1;
+ r1 = NB-o1;
+ l2 = NB+o2;
+ r2 = NB-o2;
+ if (p3>0 || n<NB) {
+ len = NB - p3;
+ if ((int)n<len) len=n;
+ if (o1>=0) x = *a1>>o1;
+ else x = *a1<<-o1;
+ if (p1+len>NB) x |= *(a1+1)<<r1;
+ a1++;
+ if (o2>=0) y = *a2>>o2;
+ else y = *a2<<-o2;
+ if (p2+len>NB) y |= *(a2+1)<<r2;
+ a2++;
+ x = m_<%=name%>(x,y);
+ *a3 = (x & (SLB(len)<<p3)) | (*a3 & ~(SLB(len)<<p3));
+ a3++;
+ n -= len;
+ }
+ if (o1==0 && o2==0) {
+ for (; n>=NB; n-=NB) {
+ x = *(a1++);
+ y = *(a2++);
+ x = m_<%=name%>(x,y);
+ *(a3++) = x;
+ }
+ } else {
+ for (; n>=NB; n-=NB) {
+ x = *a1>>o1;
+ if (o1<0) x |= *(a1-1)>>l1;
+ if (o1>0) x |= *(a1+1)<<r1;
+ a1++;
+ y = *a2>>o2;
+ if (o2<0) y |= *(a2-1)>>l2;
+ if (o2>0) y |= *(a2+1)<<r2;
+ a2++;
+ x = m_<%=name%>(x,y);
+ *(a3++) = x;
+ }
+ }
+ if (n>0) {
+ x = *a1>>o1;
+ if (o1<0) x |= *(a1-1)>>l1;
+ y = *a2>>o2;
+ if (o2<0) y |= *(a2-1)>>l2;
+ x = m_<%=name%>(x,y);
+ *a3 = (x & SLB(n)) | (*a3 & BALL<<n);
+ }
+ }
+}
+
+/*
+ Binary <%=name%>.
+ @overload <%=op_map%> other
+ @param [Numo::NArray,Numeric] other
+ @return [Numo::NArray] <%=name%> of self and other.
+*/
+static VALUE
+<%=c_func(1)%>(VALUE self, VALUE other)
+{
+ ndfunc_arg_in_t ain[2] = {{cT,0},{cT,0}};
+ ndfunc_arg_out_t aout[1] = {{cT,0}};
+ ndfunc_t ndf = { <%=c_iter%>, FULL_LOOP, 2, 1, ain, aout };
+
+ return na_ndloop(&ndf, 2, self, other);
+}
diff --git a/ext/numo/narray/gen/tmpl_bit/bit_count.c b/ext/numo/narray/gen/tmpl_bit/bit_count.c
new file mode 100644
index 0000000..48ab41e
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl_bit/bit_count.c
@@ -0,0 +1,85 @@
+#undef int_t
+#define int_t int64_t
+
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ BIT_DIGIT *a1;
+ size_t p1;
+ char *p2;
+ ssize_t s1, s2;
+ size_t *idx1;
+ BIT_DIGIT x=0;
+ int_t y;
+
+ INIT_COUNTER(lp, i);
+ INIT_PTR_BIT_IDX(lp, 0, a1, p1, s1, idx1);
+ INIT_PTR(lp, 1, p2, s2);
+ if (s2==0) {
+ GET_DATA(p2, int_t, y);
+ if (idx1) {
+ for (; i--;) {
+ LOAD_BIT(a1, p1+*idx1, x);
+ idx1++;
+ if (m_<%=name%>(x)) {
+ y++;
+ }
+ }
+ } else {
+ for (; i--;) {
+ LOAD_BIT(a1, p1, x);
+ p1 += s1;
+ if (m_<%=name%>(x)) {
+ y++;
+ }
+ }
+ }
+ *(int_t*)p2 = y;
+ } else {
+ if (idx1) {
+ for (; i--;) {
+ LOAD_BIT(a1, p1+*idx1, x);
+ idx1++;
+ if (m_<%=name%>(x)) {
+ GET_DATA(p2, int_t, y);
+ y++;
+ SET_DATA(p2, int_t, y);
+ }
+ p2+=s2;
+ }
+ } else {
+ for (; i--;) {
+ LOAD_BIT(a1, p1, x);
+ p1+=s1;
+ if (m_<%=name%>(x)) {
+ GET_DATA(p2, int_t, y);
+ y++;
+ SET_DATA(p2, int_t, y);
+ }
+ p2+=s2;
+ }
+ }
+ }
+}
+
+/*
+ Returns the number of bits.
+ If argument is supplied, return Int-array counted along the axes.
+ @overload <%=op_map%>(axis:nil, keepdims:false)
+ @param [Integer,Array,Range] axis (keyword) axes to be counted.
+ @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in the result array as dimensions with size one.
+ @return [Numo::Int64]
+*/
+static VALUE
+<%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
+{
+ VALUE v, reduce;
+ ndfunc_arg_in_t ain[3] = {{cT,0},{sym_reduce,0},{sym_init,0}};
+ ndfunc_arg_out_t aout[1] = {{numo_cInt64,0}};
+ ndfunc_t ndf = { <%=c_iter%>, FULL_LOOP_NIP, 3, 1, ain, aout };
+
+ reduce = na_reduce_dimension(argc, argv, 1, &self, &ndf, 0);
+ v = na_ndloop(&ndf, 3, self, reduce, INT2FIX(0));
+ return rb_funcall(v,rb_intern("extract"),0);
+}
diff --git a/ext/numo/narray/gen/tmpl_bit/bit_reduce.c b/ext/numo/narray/gen/tmpl_bit/bit_reduce.c
new file mode 100644
index 0000000..2b1d1df
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl_bit/bit_reduce.c
@@ -0,0 +1,129 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ BIT_DIGIT *a1, *a2;
+ size_t p1, p2;
+ ssize_t s1, s2;
+ size_t *idx1, *idx2;
+ BIT_DIGIT x=0, y=0;
+
+ INIT_COUNTER(lp, i);
+ INIT_PTR_BIT_IDX(lp, 0, a1, p1, s1, idx1);
+ INIT_PTR_BIT_IDX(lp, 1, a2, p2, s2, idx2);
+ if (idx2) {
+ if (idx1) {
+ for (; i--;) {
+ LOAD_BIT(a2, p2+*idx2, y);
+ if (y == <%=init_bit%>) {
+ LOAD_BIT(a1, p1+*idx1, x);
+ if (x != <%=init_bit%>) {
+ STORE_BIT(a2, p2+*idx2, x);
+ }
+ }
+ idx1++;
+ idx2++;
+ }
+ } else {
+ for (; i--;) {
+ LOAD_BIT(a2, p2+*idx2, y);
+ if (y == <%=init_bit%>) {
+ LOAD_BIT(a1, p1, x);
+ if (x != <%=init_bit%>) {
+ STORE_BIT(a2, p2+*idx2, x);
+ }
+ }
+ p1 += s1;
+ idx2++;
+ }
+ }
+ } else if (s2) {
+ if (idx1) {
+ for (; i--;) {
+ LOAD_BIT(a2, p2, y);
+ if (y == <%=init_bit%>) {
+ LOAD_BIT(a1, p1+*idx1, x);
+ if (x != <%=init_bit%>) {
+ STORE_BIT(a2, p2, x);
+ }
+ }
+ idx1++;
+ p2 += s2;
+ }
+ } else {
+ for (; i--;) {
+ LOAD_BIT(a2, p2, y);
+ if (y == <%=init_bit%>) {
+ LOAD_BIT(a1, p1, x);
+ if (x != <%=init_bit%>) {
+ STORE_BIT(a2, p2, x);
+ }
+ }
+ p1 += s1;
+ p2 += s2;
+ }
+ }
+ } else {
+ LOAD_BIT(a2, p2, x);
+ if (x != <%=init_bit%>) {
+ return;
+ }
+ if (idx1) {
+ for (; i--;) {
+ LOAD_BIT(a1, p1+*idx1, y);
+ if (y != <%=init_bit%>) {
+ STORE_BIT(a2, p2, y);
+ return;
+ }
+ idx1++;
+ }
+ } else {
+ for (; i--;) {
+ LOAD_BIT(a1, p1, y);
+ if (y != <%=init_bit%>) {
+ STORE_BIT(a2, p2, y);
+ return;
+ }
+ p1 += s1;
+ }
+ }
+ }
+}
+
+/*
+<% case name
+ when /^any/ %>
+ Return true if any of bits is one (true).
+<% when /^all/ %>
+ Return true if all of bits are one (true).
+<% end %>
+ If argument is supplied, return Bit-array reduced along the axes.
+ @overload <%=op_map%>(axis:nil, keepdims:false)
+ @param [Integer,Array,Range] axis (keyword) axes to be reduced.
+ @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in the result array as dimensions with size one.
+ @return [Numo::Bit] .
+*/
+static VALUE
+<%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
+{
+ VALUE v, reduce;
+ ndfunc_arg_in_t ain[3] = {{cT,0},{sym_reduce,0},{sym_init,0}};
+ ndfunc_arg_out_t aout[1] = {{numo_cBit,0}};
+ ndfunc_t ndf = {<%=c_iter%>, FULL_LOOP_NIP, 3,1, ain,aout};
+
+ reduce = na_reduce_dimension(argc, argv, 1, &self, &ndf, 0);
+ v = na_ndloop(&ndf, 3, self, reduce, INT2FIX(<%=init_bit%>));
+ if (argc > 0) {
+ return v;
+ }
+ v = <%=find_tmpl("extract").c_func%>(v);
+ switch (v) {
+ case INT2FIX(0):
+ return Qfalse;
+ case INT2FIX(1):
+ return Qtrue;
+ default:
+ rb_bug("unexpected result");
+ return v;
+ }
+}
diff --git a/ext/numo/narray/gen/tmpl_bit/each.c b/ext/numo/narray/gen/tmpl_bit/each.c
new file mode 100644
index 0000000..8825164
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl_bit/each.c
@@ -0,0 +1,44 @@
+void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ BIT_DIGIT *a1, x=0;
+ size_t p1;
+ ssize_t s1;
+ size_t *idx1;
+ VALUE y;
+
+ INIT_COUNTER(lp, i);
+ INIT_PTR_BIT_IDX(lp, 0, a1, p1, s1, idx1);
+ if (idx1) {
+ for (; i--;) {
+ LOAD_BIT(a1, p1+*idx1, x); idx1++;
+ y = m_data_to_num(x);
+ rb_yield(y);
+ }
+ } else {
+ for (; i--;) {
+ LOAD_BIT(a1, p1, x); p1+=s1;
+ y = m_data_to_num(x);
+ rb_yield(y);
+ }
+ }
+}
+
+/*
+ Calls the given block once for each element in self,
+ passing that element as a parameter.
+ @overload <%=name%>
+ @return [Numo::NArray] self
+ For a block {|x| ... }
+ @yield [x] x is element of NArray.
+*/
+static VALUE
+<%=c_func(0)%>(VALUE self)
+{
+ ndfunc_arg_in_t ain[1] = {{Qnil,0}};
+ ndfunc_t ndf = {<%=c_iter%>, FULL_LOOP_NIP, 1,0, ain,0};
+
+ na_ndloop(&ndf, 1, self);
+ return self;
+}
diff --git a/ext/numo/narray/gen/tmpl_bit/each_with_index.c b/ext/numo/narray/gen/tmpl_bit/each_with_index.c
new file mode 100644
index 0000000..3675382
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl_bit/each_with_index.c
@@ -0,0 +1,66 @@
+static inline void
+yield_each_with_index(dtype x, size_t *c, VALUE *a, int nd, int md)
+{
+ int j;
+
+ a[0] = m_data_to_num(x);
+ for (j=0; j<=nd; j++) {
+ a[j+1] = SIZET2NUM(c[j]);
+ }
+ rb_yield(rb_ary_new4(md,a));
+}
+
+
+void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ BIT_DIGIT *a1, x=0;
+ size_t p1;
+ ssize_t s1;
+ size_t *idx1;
+
+ VALUE *a;
+ size_t *c;
+ int nd, md;
+
+ c = (size_t*)(lp->opt_ptr);
+ nd = lp->ndim - 1;
+ md = lp->ndim + 1;
+ a = ALLOCA_N(VALUE,md);
+
+ INIT_COUNTER(lp, i);
+ INIT_PTR_BIT_IDX(lp, 0, a1, p1, s1, idx1);
+ c[nd] = 0;
+ if (idx1) {
+ for (; i--;) {
+ LOAD_BIT(a1, p1+*idx1, x); idx1++;
+ yield_each_with_index(x,c,a,nd,md);
+ c[nd]++;
+ }
+ } else {
+ for (; i--;) {
+ LOAD_BIT(a1, p1, x); p1+=s1;
+ yield_each_with_index(x,c,a,nd,md);
+ c[nd]++;
+ }
+ }
+}
+
+/*
+ Invokes the given block once for each element of self,
+ passing that element and indices along each axis as parameters.
+ @overload <%=name%>
+ @return [Numo::NArray] self
+ For a block {|x,i,j,...| ... }
+ @yield [x,i,j,...] x is an element, i,j,... are multidimensional indices.
+*/
+static VALUE
+<%=c_func(0)%>(VALUE self)
+{
+ ndfunc_arg_in_t ain[1] = {{Qnil,0}};
+ ndfunc_t ndf = {<%=c_iter%>, FULL_LOOP_NIP, 1,0, ain,0};
+
+ na_ndloop_with_index(&ndf, 1, self);
+ return self;
+}
diff --git a/ext/numo/narray/gen/tmpl_bit/extract.c b/ext/numo/narray/gen/tmpl_bit/extract.c
new file mode 100644
index 0000000..75ea589
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl_bit/extract.c
@@ -0,0 +1,25 @@
+/*
+ Extract an element only if self is a dimensionless NArray.
+ @overload extract
+ @return [Numeric,Numo::NArray]
+ --- Extract element value as Ruby Object if self is a dimensionless NArray,
+ otherwise returns self.
+*/
+
+static VALUE
+<%=c_func(0)%>(VALUE self)
+{
+ BIT_DIGIT *ptr, val;
+ size_t pos;
+ narray_t *na;
+ GetNArray(self,na);
+
+ if (na->ndim==0) {
+ pos = na_get_offset(self);
+ ptr = (BIT_DIGIT*)na_get_pointer_for_read(self);
+ val = ((*((ptr)+(pos)/NB)) >> ((pos)%NB)) & 1u;
+ na_release_lock(self);
+ return INT2FIX(val);
+ }
+ return self;
+}
diff --git a/ext/numo/narray/gen/tmpl_bit/fill.c b/ext/numo/narray/gen/tmpl_bit/fill.c
new file mode 100644
index 0000000..d7b04ab
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl_bit/fill.c
@@ -0,0 +1,65 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t n;
+ size_t p3;
+ ssize_t s3;
+ size_t *idx3;
+ int len;
+ BIT_DIGIT *a3;
+ BIT_DIGIT y;
+ VALUE x = lp->option;
+
+ if (x==INT2FIX(0) || x==Qfalse) {
+ y = 0;
+ } else
+ if (x==INT2FIX(1) || x==Qtrue) {
+ y = ~(BIT_DIGIT)0;
+ } else {
+ rb_raise(rb_eArgError, "invalid value for Bit");
+ }
+
+ INIT_COUNTER(lp, n);
+ INIT_PTR_BIT_IDX(lp, 0, a3, p3, s3, idx3);
+ if (idx3) {
+ y = y&1;
+ for (; n--;) {
+ STORE_BIT(a3, p3+*idx3, y); idx3++;
+ }
+ } else if (s3!=1) {
+ y = y&1;
+ for (; n--;) {
+ STORE_BIT(a3, p3, y); p3+=s3;
+ }
+ } else {
+ if (p3>0 || n<NB) {
+ len = NB - p3;
+ if ((int)n<len) len=n;
+ *a3 = (y & (SLB(len)<<p3)) | (*a3 & ~(SLB(len)<<p3));
+ a3++;
+ n -= len;
+ }
+ for (; n>=NB; n-=NB) {
+ *(a3++) = y;
+ }
+ if (n>0) {
+ *a3 = (y & SLB(n)) | (*a3 & BALL<<n);
+ }
+ }
+}
+
+/*
+ Fill elements with other.
+ @overload <%=name%> other
+ @param [Numeric] other
+ @return [Numo::<%=class_name%>] self.
+*/
+static VALUE
+<%=c_func(1)%>(VALUE self, VALUE val)
+{
+ ndfunc_arg_in_t ain[2] = {{OVERWRITE,0},{sym_option}};
+ ndfunc_t ndf = {<%=c_iter%>, FULL_LOOP, 2,0, ain,0};
+
+ na_ndloop(&ndf, 2, self, val);
+ return self;
+}
diff --git a/ext/numo/narray/gen/tmpl_bit/format.c b/ext/numo/narray/gen/tmpl_bit/format.c
new file mode 100644
index 0000000..8770f03
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl_bit/format.c
@@ -0,0 +1,61 @@
+static VALUE
+format_<%=type_name%>(VALUE fmt, dtype x)
+{
+ if (NIL_P(fmt)) {
+ char s[4];
+ int n;
+ n = m_sprintf(s,x);
+ return rb_str_new(s,n);
+ }
+ return rb_funcall(fmt, '%', 1, m_data_to_num(x));
+}
+
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ BIT_DIGIT *a1, x=0;
+ size_t p1;
+ char *p2;
+ ssize_t s1, s2;
+ size_t *idx1;
+ VALUE y;
+ VALUE fmt = lp->option;
+
+ INIT_COUNTER(lp, i);
+ INIT_PTR_BIT_IDX(lp, 0, a1, p1, s1, idx1);
+ INIT_PTR(lp, 1, p2, s2);
+
+ if (idx1) {
+ for (; i--;) {
+ LOAD_BIT(a1, p1+*idx1, x); idx1++;
+ y = format_<%=type_name%>(fmt, x);
+ SET_DATA_STRIDE(p2, s2, VALUE, y);
+ }
+ } else {
+ for (; i--;) {
+ LOAD_BIT(a1, p1, x); p1+=s1;
+ y = format_<%=type_name%>(fmt, x);
+ SET_DATA_STRIDE(p2, s2, VALUE, y);
+ }
+ }
+}
+
+/*
+ Format elements into strings.
+ @overload <%=name%> format
+ @param [String] format
+ @return [Numo::RObject] array of formated strings.
+*/
+static VALUE
+<%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
+{
+ VALUE fmt=Qnil;
+
+ ndfunc_arg_in_t ain[2] = {{Qnil,0},{sym_option}};
+ ndfunc_arg_out_t aout[1] = {{numo_cRObject,0}};
+ ndfunc_t ndf = {<%=c_iter%>, FULL_LOOP_NIP, 2,1, ain,aout};
+
+ rb_scan_args(argc, argv, "01", &fmt);
+ return na_ndloop(&ndf, 2, self, fmt);
+}
diff --git a/ext/numo/narray/gen/tmpl_bit/format_to_a.c b/ext/numo/narray/gen/tmpl_bit/format_to_a.c
new file mode 100644
index 0000000..d0dfd54
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl_bit/format_to_a.c
@@ -0,0 +1,48 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ BIT_DIGIT *a1, x=0;
+ size_t p1;
+ ssize_t s1;
+ size_t *idx1;
+ VALUE y;
+ VALUE fmt = lp->option;
+ volatile VALUE a;
+
+ INIT_COUNTER(lp, i);
+ INIT_PTR_BIT_IDX(lp, 0, a1, p1, s1, idx1);
+ a = rb_ary_new2(i);
+ rb_ary_push(lp->args[1].value, a);
+ if (idx1) {
+ for (; i--;) {
+ LOAD_BIT(a1, p1+*idx1, x); idx1++;
+ y = format_bit(fmt, x);
+ rb_ary_push(a,y);
+ }
+ } else {
+ for (; i--;) {
+ LOAD_BIT(a1, p1, x); p1+=s1;
+ y = format_bit(fmt, x);
+ rb_ary_push(a,y);
+ }
+ }
+}
+
+/*
+ Format elements into strings.
+ @overload <%=name%> format
+ @param [String] format
+ @return [Array] array of formated strings.
+*/
+static VALUE
+<%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
+{
+ volatile VALUE fmt=Qnil;
+ ndfunc_arg_in_t ain[3] = {{Qnil,0},{sym_loop_opt},{sym_option}};
+ ndfunc_arg_out_t aout[1] = {{rb_cArray,0}}; // dummy?
+ ndfunc_t ndf = {<%=c_iter%>, FULL_LOOP_NIP, 3,1, ain,aout};
+
+ rb_scan_args(argc, argv, "01", &fmt);
+ return na_ndloop_cast_narray_to_rarray(&ndf, self, fmt);
+}
diff --git a/ext/numo/narray/gen/tmpl_bit/inspect.c b/ext/numo/narray/gen/tmpl_bit/inspect.c
new file mode 100644
index 0000000..cb5cca0
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl_bit/inspect.c
@@ -0,0 +1,18 @@
+static VALUE
+<%=c_iter%>(char *ptr, size_t pos, VALUE fmt)
+{
+ dtype x;
+ LOAD_BIT(ptr,pos,x);
+ return format_<%=type_name%>(fmt, x);
+}
+
+/*
+ Returns a string containing a human-readable representation of NArray.
+ @overload inspect
+ @return [String]
+*/
+VALUE
+<%=c_func(0)%>(VALUE ary)
+{
+ return na_ndloop_inspect(ary, <%=c_iter%>, Qnil);
+}
diff --git a/ext/numo/narray/gen/tmpl_bit/mask.c b/ext/numo/narray/gen/tmpl_bit/mask.c
new file mode 100644
index 0000000..5a64787
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl_bit/mask.c
@@ -0,0 +1,132 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ BIT_DIGIT *a;
+ size_t p1, p2;
+ ssize_t s1, s2;
+ size_t *idx1, *idx2, *pidx;
+ BIT_DIGIT x=0;
+ size_t count;
+ where_opt_t *g;
+
+ g = (where_opt_t*)(lp->opt_ptr);
+ count = g->count;
+ pidx = (size_t*)(g->idx1);
+ INIT_COUNTER(lp, i);
+ INIT_PTR_BIT_IDX(lp, 0, a, p1, s1, idx1);
+ //INIT_PTR_IDX(lp, 1, p2, s2, idx2);
+ p2 = lp->args[1].iter[0].pos;
+ s2 = lp->args[1].iter[0].step;
+ idx2 = lp->args[1].iter[0].idx;
+
+ if (idx1) {
+ if (idx2) {
+ for (; i--;) {
+ LOAD_BIT(a, p1+*idx1, x);
+ idx1++;
+ if (x) {
+ *(pidx++) = p2+*idx2;
+ count++;
+ }
+ idx2++;
+ }
+ } else {
+ for (; i--;) {
+ LOAD_BIT(a, p1+*idx1, x);
+ idx1++;
+ if (x) {
+ *(pidx++) = p2;
+ count++;
+ }
+ p2 += s2;
+ }
+ }
+ } else {
+ if (idx2) {
+ for (; i--;) {
+ LOAD_BIT(a, p1, x);
+ p1 += s1;
+ if (x) {
+ *(pidx++) = p2+*idx2;
+ count++;
+ }
+ idx2++;
+ }
+ } else {
+ for (; i--;) {
+ LOAD_BIT(a, p1, x);
+ p1 += s1;
+ if (x) {
+ *(pidx++) = p2;
+ count++;
+ }
+ p2 += s2;
+ }
+ }
+ }
+ g->count = count;
+ g->idx1 = (char*)pidx;
+}
+
+#if SIZEOF_VOIDP == 8
+#define cIndex numo_cInt64
+#elif SIZEOF_VOIDP == 4
+#define cIndex numo_cInt32
+#endif
+
+/*
+ Return subarray of argument masked with self bit array.
+ @overload <%=op_map%>(array)
+ @param [Numo::NArray] array narray to be masked.
+ @return [Numo::NArray] view of masked array.
+*/
+static VALUE
+<%=c_func(1)%>(VALUE mask, VALUE val)
+{
+ volatile VALUE idx_1, view;
+ narray_data_t *nidx;
+ narray_view_t *nv;
+ narray_t *na;
+ narray_view_t *na1;
+ stridx_t stridx0;
+ size_t n_1;
+ where_opt_t g;
+ ndfunc_arg_in_t ain[2] = {{cT,0},{Qnil,0}};
+ ndfunc_t ndf = {<%=c_iter%>, FULL_LOOP, 2, 0, ain, 0};
+
+ n_1 = NUM2SIZET(<%=find_tmpl("count_true").c_func%>(0, NULL, mask));
+ idx_1 = nary_new(cIndex, 1, &n_1);
+ g.count = 0;
+ g.elmsz = SIZEOF_VOIDP;
+ g.idx1 = na_get_pointer_for_write(idx_1);
+ g.idx0 = NULL;
+ na_ndloop3(&ndf, &g, 2, mask, val);
+
+ view = na_s_allocate_view(CLASS_OF(val));
+ GetNArrayView(view, nv);
+ na_setup_shape((narray_t*)nv, 1, &n_1);
+
+ GetNArrayData(idx_1,nidx);
+ SDX_SET_INDEX(stridx0,(size_t*)nidx->ptr);
+ nidx->ptr = NULL;
+
+ nv->stridx = ALLOC_N(stridx_t,1);
+ nv->stridx[0] = stridx0;
+ nv->offset = 0;
+
+ GetNArray(val, na);
+ switch(NA_TYPE(na)) {
+ case NARRAY_DATA_T:
+ nv->data = val;
+ break;
+ case NARRAY_VIEW_T:
+ GetNArrayView(val, na1);
+ nv->data = na1->data;
+ break;
+ default:
+ rb_raise(rb_eRuntimeError,"invalid NA_TYPE: %d",NA_TYPE(na));
+ }
+
+ return view;
+}
diff --git a/ext/numo/narray/gen/tmpl_bit/none_p.c b/ext/numo/narray/gen/tmpl_bit/none_p.c
new file mode 100644
index 0000000..31e8213
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl_bit/none_p.c
@@ -0,0 +1,14 @@
+static VALUE
+<%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
+{
+ VALUE v;
+
+ v = <%=find_tmpl("any?").c_func%>(argc,argv,self);
+
+ if (v==Qtrue) {
+ return Qfalse;
+ } else if (v==Qfalse) {
+ return Qtrue;
+ }
+ return <%=find_tmpl("not").c_func%>(v);
+}
diff --git a/ext/numo/narray/gen/tmpl_bit/store_array.c b/ext/numo/narray/gen/tmpl_bit/store_array.c
new file mode 100644
index 0000000..23002da
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl_bit/store_array.c
@@ -0,0 +1,104 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i, n;
+ size_t i1, n1;
+ VALUE v1, *ptr;
+ BIT_DIGIT *a1;
+ size_t p1;
+ size_t s1, *idx1;
+ VALUE x;
+ double y;
+ BIT_DIGIT z;
+ size_t len, c;
+ double beg, step;
+
+ INIT_COUNTER(lp, n);
+ INIT_PTR_BIT_IDX(lp, 0, a1, p1, s1, idx1);
+ v1 = lp->args[1].value;
+ i = 0;
+
+ if (lp->args[1].ptr) {
+ if (v1 == Qtrue) {
+ iter_<%=type_name%>_store_<%=type_name%>(lp);
+ i = lp->args[1].shape[0];
+ if (idx1) {
+ idx1 += i;
+ } else {
+ p1 += s1 * i;
+ }
+ }
+ goto loop_end;
+ }
+
+ ptr = &v1;
+
+ switch(TYPE(v1)) {
+ case T_ARRAY:
+ n1 = RARRAY_LEN(v1);
+ ptr = RARRAY_PTR(v1);
+ break;
+ case T_NIL:
+ n1 = 0;
+ break;
+ default:
+ n1 = 1;
+ }
+
+ if (idx1) {
+ for (i=i1=0; i1<n1 && i<n; i++,i1++) {
+ x = ptr[i1];
+ if (rb_obj_is_kind_of(x, rb_cRange) || rb_obj_is_kind_of(x, na_cStep)) {
+ nary_step_sequence(x,&len,&beg,&step);
+ for (c=0; c<len && i<n; c++,i++) {
+ y = beg + step * c;
+ z = m_from_double(y);
+ STORE_BIT(a1, p1+*idx1, z); idx1++;
+ }
+ }
+ if (TYPE(x) != T_ARRAY) {
+ if (x == Qnil) x = INT2FIX(0);
+ z = m_num_to_data(x);
+ STORE_BIT(a1, p1+*idx1, z); idx1++;
+ }
+ }
+ } else {
+ for (i=i1=0; i1<n1 && i<n; i++,i1++) {
+ x = ptr[i1];
+ if (rb_obj_is_kind_of(x, rb_cRange) || rb_obj_is_kind_of(x, na_cStep)) {
+ nary_step_sequence(x,&len,&beg,&step);
+ for (c=0; c<len && i<n; c++,i++) {
+ y = beg + step * c;
+ z = m_from_double(y);
+ STORE_BIT(a1, p1, z); p1+=s1;
+ }
+ }
+ if (TYPE(x) != T_ARRAY) {
+ z = m_num_to_data(x);
+ STORE_BIT(a1, p1, z); p1+=s1;
+ }
+ }
+ }
+
+ loop_end:
+ z = m_zero;
+ if (idx1) {
+ for (; i<n; i++) {
+ STORE_BIT(a1, p1+*idx1, z); idx1++;
+ }
+ } else {
+ for (; i<n; i++) {
+ STORE_BIT(a1, p1, z); p1+=s1;
+ }
+ }
+}
+
+static VALUE
+<%=c_func(:nodef)%>(VALUE self, VALUE rary)
+{
+ ndfunc_arg_in_t ain[2] = {{OVERWRITE,0}, {rb_cArray,0}};
+ ndfunc_t ndf = {<%=c_iter%>, FULL_LOOP, 2, 0, ain, 0};
+
+ na_ndloop_store_rarray(&ndf, self, rary);
+ return self;
+}
diff --git a/ext/numo/narray/gen/tmpl_bit/store_bit.c b/ext/numo/narray/gen/tmpl_bit/store_bit.c
new file mode 100644
index 0000000..e2eb50a
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl_bit/store_bit.c
@@ -0,0 +1,66 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t n;
+ size_t p1, p3;
+ ssize_t s1, s3;
+ size_t *idx1, *idx3;
+ int o1, l1, r1, len;
+ BIT_DIGIT *a1, *a3;
+ BIT_DIGIT x;
+
+ INIT_COUNTER(lp, n);
+ INIT_PTR_BIT_IDX(lp, 0, a3, p3, s3, idx3);
+ INIT_PTR_BIT_IDX(lp, 1, a1, p1, s1, idx1);
+ if (s1!=1 || s3!=1 || idx1 || idx3) {
+ for (; n--;) {
+ LOAD_BIT_STEP(a1, p1, s1, idx1, x);
+ STORE_BIT_STEP(a3, p3, s3, idx3, x);
+ }
+ } else {
+ o1 = p1 % NB;
+ o1 -= p3;
+ l1 = NB+o1;
+ r1 = NB-o1;
+ if (p3>0 || n<NB) {
+ len = NB - p3;
+ if ((int)n<len) len=n;
+ if (o1>=0) x = *a1>>o1;
+ else x = *a1<<-o1;
+ if (p1+len>NB) x |= *(a1+1)<<r1;
+ a1++;
+ *a3 = (x & (SLB(len)<<p3)) | (*a3 & ~(SLB(len)<<p3));
+ a3++;
+ n -= len;
+ }
+ if (o1==0) {
+ for (; n>=NB; n-=NB) {
+ x = *(a1++);
+ *(a3++) = x;
+ }
+ } else {
+ for (; n>=NB; n-=NB) {
+ x = *a1>>o1;
+ if (o1<0) x |= *(a1-1)>>l1;
+ if (o1>0) x |= *(a1+1)<<r1;
+ a1++;
+ *(a3++) = x;
+ }
+ }
+ if (n>0) {
+ x = *a1>>o1;
+ if (o1<0) x |= *(a1-1)>>l1;
+ *a3 = (x & SLB(n)) | (*a3 & BALL<<n);
+ }
+ }
+}
+
+static VALUE
+<%=c_func(:nodef)%>(VALUE self, VALUE obj)
+{
+ ndfunc_arg_in_t ain[2] = {{OVERWRITE,0},{Qnil,0}};
+ ndfunc_t ndf = {<%=c_iter%>, FULL_LOOP, 2,0, ain,0};
+
+ na_ndloop(&ndf, 2, self, obj);
+ return self;
+}
diff --git a/ext/numo/narray/gen/tmpl_bit/store_from.c b/ext/numo/narray/gen/tmpl_bit/store_from.c
new file mode 100644
index 0000000..84330d9
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl_bit/store_from.c
@@ -0,0 +1,56 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ ssize_t i, s1, s2;
+ size_t p1;
+ char *p2;
+ size_t *idx1, *idx2;
+ <%=dtype%> x;
+ BIT_DIGIT *a1;
+ BIT_DIGIT y;
+
+ INIT_COUNTER(lp, i);
+ INIT_PTR_BIT_IDX(lp, 0, a1, p1, s1, idx1);
+ INIT_PTR_IDX(lp, 1, p2, s2, idx2);
+
+ if (idx2) {
+ if (idx1) {
+ for (; i--;) {
+ GET_DATA_INDEX(p2,idx2,<%=dtype%>,x);
+ y = <%=macro%>(x);
+ STORE_BIT(a1, p1+*idx1, y); idx1++;
+ }
+ } else {
+ for (; i--;) {
+ GET_DATA_INDEX(p2,idx2,<%=dtype%>,x);
+ y = <%=macro%>(x);
+ STORE_BIT(a1, p1, y); p1+=s1;
+ }
+ }
+ } else {
+ if (idx1) {
+ for (; i--;) {
+ GET_DATA_STRIDE(p2,s2,<%=dtype%>,x);
+ y = <%=macro%>(x);
+ STORE_BIT(a1, p1+*idx1, y); idx1++;
+ }
+ } else {
+ for (; i--;) {
+ GET_DATA_STRIDE(p2,s2,<%=dtype%>,x);
+ y = <%=macro%>(x);
+ STORE_BIT(a1, p1, y); p1+=s1;
+ }
+ }
+ }
+}
+
+
+static VALUE
+<%=c_func(:nodef)%>(VALUE self, VALUE obj)
+{
+ ndfunc_arg_in_t ain[2] = {{OVERWRITE,0},{Qnil,0}};
+ ndfunc_t ndf = {<%=c_iter%>, FULL_LOOP, 2,0, ain,0};
+
+ na_ndloop(&ndf, 2, self, obj);
+ return self;
+}
diff --git a/ext/numo/narray/gen/tmpl_bit/to_a.c b/ext/numo/narray/gen/tmpl_bit/to_a.c
new file mode 100644
index 0000000..fef82a2
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl_bit/to_a.c
@@ -0,0 +1,43 @@
+void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ BIT_DIGIT *a1;
+ size_t p1;
+ ssize_t s1;
+ size_t *idx1;
+ BIT_DIGIT x=0;
+ VALUE a, y;
+
+ INIT_COUNTER(lp, i);
+ INIT_PTR_BIT_IDX(lp, 0, a1, p1, s1, idx1);
+ a = rb_ary_new2(i);
+ rb_ary_push(lp->args[1].value, a);
+ if (idx1) {
+ for (; i--;) {
+ LOAD_BIT(a1,p1+*idx1,x); idx1++;
+ y = m_data_to_num(x);
+ rb_ary_push(a,y);
+ }
+ } else {
+ for (; i--;) {
+ LOAD_BIT(a1,p1,x); p1+=s1;
+ y = m_data_to_num(x);
+ rb_ary_push(a,y);
+ }
+ }
+}
+
+/*
+ Convert self to Array.
+ @overload <%=name%>
+ @return [Array]
+*/
+static VALUE
+<%=c_func(0)%>(VALUE self)
+{
+ ndfunc_arg_in_t ain[3] = {{Qnil,0},{sym_loop_opt},{sym_option}};
+ ndfunc_arg_out_t aout[1] = {{rb_cArray,0}}; // dummy?
+ ndfunc_t ndf = {<%=c_iter%>, FULL_LOOP_NIP, 3,1, ain,aout};
+ return na_ndloop_cast_narray_to_rarray(&ndf, self, Qnil);
+}
diff --git a/ext/numo/narray/gen/tmpl_bit/unary.c b/ext/numo/narray/gen/tmpl_bit/unary.c
new file mode 100644
index 0000000..0d6434a
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl_bit/unary.c
@@ -0,0 +1,77 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t n;
+ size_t p1, p3;
+ ssize_t s1, s3;
+ size_t *idx1, *idx3;
+ int o1, l1, r1, len;
+ BIT_DIGIT *a1, *a3;
+ BIT_DIGIT x;
+ BIT_DIGIT y;
+
+ INIT_COUNTER(lp, n);
+ INIT_PTR_BIT_IDX(lp, 0, a1, p1, s1, idx1);
+ INIT_PTR_BIT_IDX(lp, 1, a3, p3, s3, idx3);
+ if (s1!=1 || s3!=1 || idx1 || idx3) {
+ for (; n--;) {
+ LOAD_BIT_STEP(a1, p1, s1, idx1, x);
+ y = m_<%=name%>(x);
+ STORE_BIT_STEP(a3, p3, s3, idx3, y);
+ }
+ } else {
+ o1 = p1 % NB;
+ o1 -= p3;
+ l1 = NB+o1;
+ r1 = NB-o1;
+ if (p3>0 || n<NB) {
+ len = NB - p3;
+ if ((int)n<len) len=n;
+ if (o1>=0) x = *a1>>o1;
+ else x = *a1<<-o1;
+ if (p1+len>NB) x |= *(a1+1)<<r1;
+ a1++;
+ y = m_<%=name%>(x);
+ *a3 = (y & (SLB(len)<<p3)) | (*a3 & ~(SLB(len)<<p3));
+ a3++;
+ n -= len;
+ }
+ if (o1==0) {
+ for (; n>=NB; n-=NB) {
+ x = *(a1++);
+ y = m_<%=name%>(x);
+ *(a3++) = y;
+ }
+ } else {
+ for (; n>=NB; n-=NB) {
+ x = *a1>>o1;
+ if (o1<0) x |= *(a1-1)>>l1;
+ if (o1>0) x |= *(a1+1)<<r1;
+ a1++;
+ y = m_<%=name%>(x);
+ *(a3++) = y;
+ }
+ }
+ if (n>0) {
+ x = *a1>>o1;
+ if (o1<0) x |= *(a1-1)>>l1;
+ y = m_<%=name%>(x);
+ *a3 = (y & SLB(n)) | (*a3 & BALL<<n);
+ }
+ }
+}
+
+/*
+ Unary <%=name%>.
+ @overload <%=name%>
+ @return [Numo::<%=class_name%>] <%=name%> of self.
+*/
+static VALUE
+<%=c_func(0)%>(VALUE self)
+{
+ ndfunc_arg_in_t ain[1] = {{cT,0}};
+ ndfunc_arg_out_t aout[1] = {{cT,0}};
+ ndfunc_t ndf = {<%=c_iter%>, FULL_LOOP, 1,1, ain,aout};
+
+ return na_ndloop(&ndf, 1, self);
+}
diff --git a/ext/numo/narray/gen/tmpl_bit/where.c b/ext/numo/narray/gen/tmpl_bit/where.c
new file mode 100644
index 0000000..9760e6d
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl_bit/where.c
@@ -0,0 +1,86 @@
+typedef struct {
+ size_t count;
+ char *idx0;
+ char *idx1;
+ size_t elmsz;
+} where_opt_t;
+
+#define STORE_INT(ptr, esz, x) memcpy(ptr,&(x),esz)
+
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ BIT_DIGIT *a;
+ size_t p;
+ ssize_t s;
+ size_t *idx;
+ BIT_DIGIT x=0;
+ char *idx1;
+ size_t count;
+ size_t e;
+ where_opt_t *g;
+
+ g = (where_opt_t*)(lp->opt_ptr);
+ count = g->count;
+ idx1 = g->idx1;
+ e = g->elmsz;
+ INIT_COUNTER(lp, i);
+ INIT_PTR_BIT_IDX(lp, 0, a, p, s, idx);
+ if (idx) {
+ for (; i--;) {
+ LOAD_BIT(a, p+*idx, x);
+ idx++;
+ if (x!=0) {
+ STORE_INT(idx1,e,count);
+ idx1 += e;
+ }
+ count++;
+ }
+ } else {
+ for (; i--;) {
+ LOAD_BIT(a, p, x);
+ p+=s;
+ if (x!=0) {
+ STORE_INT(idx1,e,count);
+ idx1 += e;
+ }
+ count++;
+ }
+ }
+ g->count = count;
+ g->idx1 = idx1;
+}
+
+/*
+ Returns the array of index where the bit is one (true).
+ @overload <%=op_map%>
+ @return [Numo::Int32,Numo::Int64]
+*/
+static VALUE
+<%=c_func(0)%>(VALUE self)
+{
+ volatile VALUE idx_1;
+ size_t size, n_1;
+ where_opt_t *g;
+
+ ndfunc_arg_in_t ain[1] = {{cT,0}};
+ ndfunc_t ndf = { <%=c_iter%>, FULL_LOOP, 1, 0, ain, 0 };
+
+ size = RNARRAY_SIZE(self);
+ n_1 = NUM2SIZET(<%=find_tmpl("count_true").c_func%>(0, NULL, self));
+ g = ALLOCA_N(where_opt_t,1);
+ g->count = 0;
+ if (size>4294967295ul) {
+ idx_1 = nary_new(numo_cInt64, 1, &n_1);
+ g->elmsz = 8;
+ } else {
+ idx_1 = nary_new(numo_cInt32, 1, &n_1);
+ g->elmsz = 4;
+ }
+ g->idx1 = na_get_pointer_for_write(idx_1);
+ g->idx0 = NULL;
+ na_ndloop3(&ndf, g, 1, self);
+ na_release_lock(idx_1);
+ return idx_1;
+}
diff --git a/ext/numo/narray/gen/tmpl_bit/where2.c b/ext/numo/narray/gen/tmpl_bit/where2.c
new file mode 100644
index 0000000..de28efe
--- /dev/null
+++ b/ext/numo/narray/gen/tmpl_bit/where2.c
@@ -0,0 +1,91 @@
+static void
+<%=c_iter%>(na_loop_t *const lp)
+{
+ size_t i;
+ BIT_DIGIT *a;
+ size_t p;
+ ssize_t s;
+ size_t *idx;
+ BIT_DIGIT x=0;
+ char *idx0, *idx1;
+ size_t count;
+ size_t e;
+ where_opt_t *g;
+
+ g = (where_opt_t*)(lp->opt_ptr);
+ count = g->count;
+ idx0 = g->idx0;
+ idx1 = g->idx1;
+ e = g->elmsz;
+ INIT_COUNTER(lp, i);
+ INIT_PTR_BIT_IDX(lp, 0, a, p, s, idx);
+ if (idx) {
+ for (; i--;) {
+ LOAD_BIT(a, p+*idx, x);
+ idx++;
+ if (x==0) {
+ STORE_INT(idx0,e,count);
+ idx0 += e;
+ } else {
+ STORE_INT(idx1,e,count);
+ idx1 += e;
+ }
+ count++;
+ }
+ } else {
+ for (; i--;) {
+ LOAD_BIT(a, p, x);
+ p+=s;
+ if (x==0) {
+ STORE_INT(idx0,e,count);
+ idx0 += e;
+ } else {
+ STORE_INT(idx1,e,count);
+ idx1 += e;
+ }
+ count++;
+ }
+ }
+ g->count = count;
+ g->idx0 = idx0;
+ g->idx1 = idx1;
+}
+
+/*
+ Returns two index arrays.
+ The first array contains index where the bit is one (true).
+ The second array contains index where the bit is zero (false).
+ @overload <%=op_map%>
+ @return [Numo::Int32,Numo::Int64]*2
+*/
+static VALUE
+<%=c_func(0)%>(VALUE self)
+{
+ VALUE idx_1, idx_0;
+ size_t size, n_1, n_0;
+ where_opt_t *g;
+
+ ndfunc_arg_in_t ain[1] = {{cT,0}};
+ ndfunc_t ndf = { <%=c_iter%>, FULL_LOOP, 1, 0, ain, 0 };
+
+ size = RNARRAY_SIZE(self);
+ n_1 = NUM2SIZET(<%=find_tmpl("count_true").c_func%>(0, NULL, self));
+ n_0 = size - n_1;
+ g = ALLOCA_N(where_opt_t,1);
+ g->count = 0;
+ if (size>4294967295ul) {
+ idx_1 = nary_new(numo_cInt64, 1, &n_1);
+ idx_0 = nary_new(numo_cInt64, 1, &n_0);
+ g->elmsz = 8;
+ } else {
+ idx_1 = nary_new(numo_cInt32, 1, &n_1);
+ idx_0 = nary_new(numo_cInt32, 1, &n_0);
+ g->elmsz = 4;
+ }
+ g->idx1 = na_get_pointer_for_write(idx_1);
+ g->idx0 = na_get_pointer_for_write(idx_0);
+ na_ndloop3(&ndf, g, 1, self);
+ na_release_lock(idx_0);
+ na_release_lock(idx_1);
+ return rb_assoc_new(idx_1,idx_0);
+}
diff --git a/ext/numo/narray/index.c b/ext/numo/narray/index.c
new file mode 100644
index 0000000..3a649b3
--- /dev/null
+++ b/ext/numo/narray/index.c
@@ -0,0 +1,842 @@
+/*
+ index.c
+ Numerical Array Extension for Ruby
+ (C) Copyright 1999-2017 by Masahiro TANAKA
+*/
+//#define NARRAY_C
+
+#include <string.h>
+#include <ruby.h>
+#include "numo/narray.h"
+#include "numo/template.h"
+
+#if SIZEOF_VOIDP == 8
+#define cIndex numo_cInt64
+#elif SIZEOF_VOIDP == 4
+#define cIndex numo_cInt32
+#endif
+
+// from ruby/enumerator.c
+struct enumerator {
+ VALUE obj;
+ ID meth;
+ VALUE args;
+ // use only above in this source
+ VALUE fib;
+ VALUE dst;
+ VALUE lookahead;
+ VALUE feedvalue;
+ VALUE stop_exc;
+ VALUE size;
+ // incompatible below depending on ruby version
+ //VALUE procs; // ruby 2.4
+ //rb_enumerator_size_func *size_fn; // ruby 2.1-2.4
+ //VALUE (*size_fn)(ANYARGS); // ruby 2.0
+};
+
+// note: the memory refed by this pointer is not freed and causes memroy leak.
+typedef struct {
+ size_t n; // the number of elements of the dimesnion
+ size_t beg; // the starting point in the dimension
+ ssize_t step; // the step size of the dimension
+ size_t *idx; // list of indices
+ int reduce; // true if the dimension is reduced by addition
+ int orig_dim; // the dimension of original array
+} na_index_arg_t;
+
+
+static void
+print_index_arg(na_index_arg_t *q, int n)
+{
+ int i;
+ printf("na_index_arg_t = 0x%"SZF"x {\n",(size_t)q);
+ for (i=0; i<n; i++) {
+ printf(" q[%d].n=%"SZF"d\n",i,q[i].n);
+ printf(" q[%d].beg=%"SZF"d\n",i,q[i].beg);
+ printf(" q[%d].step=%"SZF"d\n",i,q[i].step);
+ printf(" q[%d].idx=0x%"SZF"x\n",i,(size_t)q[i].idx);
+ printf(" q[%d].reduce=0x%x\n",i,q[i].reduce);
+ printf(" q[%d].orig_dim=%d\n",i,q[i].orig_dim);
+ }
+ printf("}\n");
+}
+
+static VALUE sym_ast;
+static VALUE sym_all;
+//static VALUE sym_reduce;
+static VALUE sym_minus;
+static VALUE sym_new;
+static VALUE sym_reverse;
+static VALUE sym_plus;
+static VALUE sym_sum;
+static VALUE sym_tilde;
+static VALUE sym_rest;
+static ID id_beg;
+static ID id_end;
+static ID id_exclude_end;
+static ID id_each;
+static ID id_step;
+static ID id_dup;
+static ID id_bracket;
+static ID id_shift_left;
+static ID id_mask;
+
+
+void
+na_index_set_step(na_index_arg_t *q, int i, size_t n, size_t beg, ssize_t step)
+{
+ q->n = n;
+ q->beg = beg;
+ q->step = step;
+ q->idx = NULL;
+ q->reduce = 0;
+ q->orig_dim = i;
+}
+
+void
+na_index_set_scalar(na_index_arg_t *q, int i, ssize_t size, ssize_t x)
+{
+ if (x < -size || x >= size)
+ rb_raise(rb_eRangeError,
+ "array index (%"SZF"d) is out of array size (%"SZF"d)",
+ x, size);
+ if (x < 0)
+ x += size;
+ q->n = 1;
+ q->beg = x;
+ q->step = 0;
+ q->idx = NULL;
+ q->reduce = 0;
+ q->orig_dim = i;
+}
+
+static inline ssize_t
+na_range_check(ssize_t pos, ssize_t size, int dim)
+{
+ ssize_t idx=pos;
+
+ if (idx < 0) idx += size;
+ if (idx < 0 || idx >= size) {
+ rb_raise(rb_eIndexError, "index=%"SZF"d out of shape[%d]=%"SZF"d",
+ pos, dim, size);
+ }
+ return idx;
+}
+
+static void
+na_parse_array(VALUE ary, int orig_dim, ssize_t size, na_index_arg_t *q)
+{
+ int k;
+ int n = RARRAY_LEN(ary);
+ q->idx = ALLOC_N(size_t, n);
+ for (k=0; k<n; k++) {
+ q->idx[k] = na_range_check(NUM2SSIZET(RARRAY_AREF(ary,k)), size, orig_dim);
+ }
+ q->n = n;
+ q->beg = 0;
+ q->step = 1;
+ q->reduce = 0;
+ q->orig_dim = orig_dim;
+}
+
+static void
+na_parse_narray_index(VALUE a, int orig_dim, ssize_t size, na_index_arg_t *q)
+{
+ VALUE idx;
+ narray_t *na;
+ narray_data_t *nidx;
+ size_t k, n;
+ ssize_t *nidxp;
+
+ GetNArray(a,na);
+ if (NA_NDIM(na) != 1) {
+ rb_raise(rb_eIndexError, "should be 1-d NArray");
+ }
+ n = NA_SIZE(na);
+ idx = nary_new(cIndex,1,&n);
+ na_store(idx,a);
+
+ GetNArrayData(idx,nidx);
+ nidxp = (ssize_t*)nidx->ptr;
+ q->idx = ALLOC_N(size_t, n);
+ for (k=0; k<n; k++) {
+ q->idx[k] = na_range_check(nidxp[k], size, orig_dim);
+ }
+ q->n = n;
+ q->beg = 0;
+ q->step = 1;
+ q->reduce = 0;
+ q->orig_dim = orig_dim;
+}
+
+static void
+na_parse_range(VALUE range, ssize_t step, int orig_dim, ssize_t size, na_index_arg_t *q)
+{
+ int n;
+ ssize_t beg, end;
+
+ beg = NUM2LONG(rb_funcall(range,id_beg,0));
+ if (beg<0) {
+ beg += size;
+ }
+
+ end = NUM2LONG(rb_funcall(range,id_end,0));
+ if (end<0) {
+ end += size;
+ }
+
+ if (RTEST(rb_funcall(range,id_exclude_end,0))) {
+ end--;
+ }
+ if (beg < -size || beg >= size ||
+ end < -size || end >= size) {
+ rb_raise(rb_eRangeError,
+ "beg=%"SZF"d,end=%"SZF"d is out of array size (%"SZF"d)",
+ beg, end, size);
+ }
+ n = (end-beg)/step+1;
+ if (n<0) n=0;
+ na_index_set_step(q,orig_dim,n,beg,step);
+
+}
+
+static void
+na_parse_enumerator(VALUE enum_obj, int orig_dim, ssize_t size, na_index_arg_t *q)
+{
+ int len;
+ ssize_t step;
+ struct enumerator *e;
+
+ if (!RB_TYPE_P(enum_obj, T_DATA)) {
+ rb_raise(rb_eTypeError,"wrong argument type (not T_DATA)");
+ }
+ e = (struct enumerator *)DATA_PTR(enum_obj);
+
+ if (rb_obj_is_kind_of(e->obj, rb_cRange)) {
+ if (e->meth == id_each) {
+ na_parse_range(e->obj, 1, orig_dim, size, q);
+ }
+ else if (e->meth == id_step) {
+ if (TYPE(e->args) != T_ARRAY) {
+ rb_raise(rb_eArgError,"no argument for step");
+ }
+ len = RARRAY_LEN(e->args);
+ if (len != 1) {
+ rb_raise(rb_eArgError,"invalid number of step argument (1 for %d)",len);
+ }
+ step = NUM2SSIZET(RARRAY_AREF(e->args,0));
+ na_parse_range(e->obj, step, orig_dim, size, q);
+ } else {
+ rb_raise(rb_eTypeError,"unknown Range method: %s",rb_id2name(e->meth));
+ }
+ } else {
+ rb_raise(rb_eTypeError,"not Range object");
+ }
+}
+
+// Analyze *a* which is *i*-th index object and store the information to q
+//
+// a: a ruby object of i-th index
+// size: size of i-th dimension of original NArray
+// i: parse i-th index
+// q: parsed information is stored to *q
+static void
+na_index_parse_each(volatile VALUE a, ssize_t size, int i, na_index_arg_t *q)
+{
+ switch(TYPE(a)) {
+
+ case T_FIXNUM:
+ na_index_set_scalar(q,i,size,FIX2LONG(a));
+ break;
+
+ case T_BIGNUM:
+ na_index_set_scalar(q,i,size,NUM2SSIZET(a));
+ break;
+
+ case T_FLOAT:
+ na_index_set_scalar(q,i,size,NUM2SSIZET(a));
+ break;
+
+ case T_NIL:
+ case T_TRUE:
+ na_index_set_step(q,i,size,0,1);
+ break;
+
+ case T_SYMBOL:
+ if (a==sym_all || a==sym_ast) {
+ na_index_set_step(q,i,size,0,1);
+ }
+ else if (a==sym_reverse) {
+ na_index_set_step(q,i,size,size-1,-1);
+ }
+ else if (a==sym_new) {
+ na_index_set_step(q,i,1,0,1);
+ }
+ else if (a==sym_reduce || a==sym_sum || a==sym_plus) {
+ na_index_set_step(q,i,size,0,1);
+ q->reduce = 1;
+ } else {
+ rb_raise(rb_eIndexError, "invalid symbol for index");
+ }
+ break;
+
+ case T_ARRAY:
+ na_parse_array(a, i, size, q);
+ break;
+
+ default:
+ if (rb_obj_is_kind_of(a, rb_cRange)) {
+ na_parse_range(a, 1, i, size, q);
+ }
+ else if (rb_obj_is_kind_of(a, rb_cEnumerator)) {
+ na_parse_enumerator(a, i, size, q);
+ }
+ else if (rb_obj_is_kind_of(a, na_cStep)) {
+ ssize_t beg, step, n;
+ nary_step_array_index(a, size, (size_t*)(&n), &beg, &step);
+ na_index_set_step(q,i,n,beg,step);
+ }
+ // NArray index
+ else if (NA_IsNArray(a)) {
+ na_parse_narray_index(a, i, size, q);
+ }
+ else {
+ rb_raise(rb_eIndexError, "not allowed type");
+ }
+ }
+}
+
+
+static size_t
+na_index_parse_args(VALUE args, narray_t *na, na_index_arg_t *q, int ndim)
+{
+ int i, j, k, l, nidx;
+ size_t total=1;
+ VALUE v;
+
+ nidx = RARRAY_LEN(args);
+
+ for (i=j=k=0; i<nidx; i++) {
+ v = RARRAY_AREF(args,i);
+ // rest (ellipsis) dimension
+ if (v==Qfalse) {
+ for (l = ndim - (nidx-1); l>0; l--) {
+ //printf("i=%d j=%d k=%d l=%d ndim=%d nidx=%d\n",i,j,k,l,ndim,nidx);
+ na_index_parse_each(Qtrue, na->shape[k], k, &q[j]);
+ if (q[j].n > 1) {
+ total *= q[j].n;
+ }
+ j++;
+ k++;
+ }
+ }
+ // new dimension
+ else if (v==sym_new) {
+ na_index_parse_each(v, 1, k, &q[j]);
+ j++;
+ }
+ // other dimention
+ else {
+ na_index_parse_each(v, na->shape[k], k, &q[j]);
+ if (q[j].n > 1) {
+ total *= q[j].n;
+ }
+ j++;
+ k++;
+ }
+ }
+ return total;
+}
+
+
+static void
+na_get_strides_nadata(const narray_data_t *na, ssize_t *strides, ssize_t elmsz)
+{
+ int i = na->base.ndim - 1;
+ strides[i] = elmsz;
+ for (; i>0; i--) {
+ strides[i-1] = strides[i] * na->base.shape[i];
+ }
+}
+
+static void
+na_index_aref_nadata(narray_data_t *na1, narray_view_t *na2,
+ na_index_arg_t *q, ssize_t elmsz, int ndim, int keep_dim)
+{
+ int i, j;
+ ssize_t size, k, total=1;
+ ssize_t stride1;
+ ssize_t *strides_na1;
+ size_t *index;
+ ssize_t beg, step;
+ VALUE m;
+
+ strides_na1 = ALLOCA_N(ssize_t, na1->base.ndim);
+ na_get_strides_nadata(na1, strides_na1, elmsz);
+
+ for (i=j=0; i<ndim; i++) {
+ stride1 = strides_na1[q[i].orig_dim];
+
+ // numeric index -- trim dimension
+ if (!keep_dim && q[i].n==1 && q[i].step==0) {
+ beg = q[i].beg;
+ na2->offset += stride1 * beg;
+ continue;
+ }
+
+ na2->base.shape[j] = size = q[i].n;
+
+ if (q[i].reduce != 0) {
+ m = rb_funcall(INT2FIX(1),id_shift_left,1,INT2FIX(j));
+ na2->base.reduce = rb_funcall(m,'|',1,na2->base.reduce);
+ }
+
+ // array index
+ if (q[i].idx != NULL) {
+ index = q[i].idx;
+ SDX_SET_INDEX(na2->stridx[j],index);
+ q[i].idx = NULL;
+ for (k=0; k<size; k++) {
+ index[k] = index[k] * stride1;
+ }
+ } else {
+ beg = q[i].beg;
+ step = q[i].step;
+ na2->offset += stride1*beg;
+ SDX_SET_STRIDE(na2->stridx[j], stride1*step);
+ }
+ j++;
+ total *= size;
+ }
+ na2->base.size = total;
+}
+
+
+static void
+na_index_aref_naview(narray_view_t *na1, narray_view_t *na2,
+ na_index_arg_t *q, ssize_t elmsz, int ndim, int keep_dim)
+{
+ int i, j;
+ ssize_t total=1;
+
+ for (i=j=0; i<ndim; i++) {
+ stridx_t sdx1 = na1->stridx[q[i].orig_dim];
+ ssize_t size;
+
+ // numeric index -- trim dimension
+ if (!keep_dim && q[i].n==1 && q[i].step==0) {
+ if (SDX_IS_INDEX(sdx1)) {
+ na2->offset += SDX_GET_INDEX(sdx1)[q[i].beg];
+ } else {
+ na2->offset += SDX_GET_STRIDE(sdx1)*q[i].beg;
+ }
+ continue;
+ }
+
+ na2->base.shape[j] = size = q[i].n;
+
+ if (q[i].reduce != 0) {
+ VALUE m = rb_funcall(INT2FIX(1),id_shift_left,1,INT2FIX(j));
+ na2->base.reduce = rb_funcall(m,'|',1,na2->base.reduce);
+ }
+
+ if (q[i].orig_dim >= na1->base.ndim) {
+ // new dimension
+ SDX_SET_STRIDE(na2->stridx[j], elmsz);
+ }
+ else if (q[i].idx != NULL && SDX_IS_INDEX(sdx1)) {
+ // index <- index
+ int k;
+ size_t *index = q[i].idx;
+ SDX_SET_INDEX(na2->stridx[j], index);
+ q[i].idx = NULL;
+
+ for (k=0; k<size; k++) {
+ index[k] = SDX_GET_INDEX(sdx1)[index[k]];
+ }
+ }
+ else if (q[i].idx != NULL && SDX_IS_STRIDE(sdx1)) {
+ // index <- step
+ ssize_t stride1 = SDX_GET_STRIDE(sdx1);
+ size_t *index = q[i].idx;
+ SDX_SET_INDEX(na2->stridx[j],index);
+ q[i].idx = NULL;
+
+ if (stride1<0) {
+ size_t last;
+ int k;
+ stride1 = -stride1;
+ last = na1->base.shape[q[i].orig_dim] - 1;
+ if (na2->offset < last * stride1) {
+ rb_raise(rb_eStandardError,"bug: negative offset");
+ }
+ na2->offset -= last * stride1;
+ for (k=0; k<size; k++) {
+ index[k] = (last - index[k]) * stride1;
+ }
+ } else {
+ int k;
+ for (k=0; k<size; k++) {
+ index[k] = index[k] * stride1;
+ }
+ }
+ }
+ else if (q[i].idx == NULL && SDX_IS_INDEX(sdx1)) {
+ // step <- index
+ int k;
+ size_t beg = q[i].beg;
+ ssize_t step = q[i].step;
+ size_t *index = ALLOC_N(size_t, size);
+ SDX_SET_INDEX(na2->stridx[j],index);
+ for (k=0; k<size; k++) {
+ index[k] = SDX_GET_INDEX(sdx1)[beg+step*k];
+ }
+ }
+ else if (q[i].idx == NULL && SDX_IS_STRIDE(sdx1)) {
+ // step <- step
+ size_t beg = q[i].beg;
+ ssize_t step = q[i].step;
+ ssize_t stride1 = SDX_GET_STRIDE(sdx1);
+ na2->offset += stride1*beg;
+ SDX_SET_STRIDE(na2->stridx[j], stride1*step);
+ }
+
+ j++;
+ total *= size;
+ }
+ na2->base.size = total;
+}
+
+
+static int
+na_ndim_new_narray(int ndim, const na_index_arg_t *q)
+{
+ int i, ndim_new=0;
+ for (i=0; i<ndim; i++) {
+ if (q[i].n>1 || q[i].step!=0) {
+ ndim_new++;
+ }
+ }
+ return ndim_new;
+}
+
+typedef struct {
+ VALUE args, self, store;
+ int ndim;
+ na_index_arg_t *q;
+ narray_t *na1;
+ int keep_dim;
+} na_aref_md_data_t;
+
+static na_index_arg_t*
+na_allocate_index_args(int ndim)
+{
+ na_index_arg_t *q = ALLOC_N(na_index_arg_t, ndim);
+ int i;
+
+ for (i=0; i<ndim; i++) {
+ q[i].idx = NULL;
+ }
+ return q;
+}
+
+static
+VALUE na_aref_md_protected(VALUE data_value)
+{
+ na_aref_md_data_t *data = (na_aref_md_data_t*)(data_value);
+ VALUE self = data->self;
+ VALUE args = data->args;
+ VALUE store = data->store;
+ int ndim = data->ndim;
+ na_index_arg_t *q = data->q;
+ narray_t *na1 = data->na1;
+ int keep_dim = data->keep_dim;
+
+ int ndim_new;
+ VALUE view;
+ narray_view_t *na2;
+ ssize_t elmsz;
+
+ na_index_parse_args(args, na1, q, ndim);
+
+ if (na_debug_flag) print_index_arg(q,ndim);
+
+ if (keep_dim) {
+ ndim_new = ndim;
+ } else {
+ ndim_new = na_ndim_new_narray(ndim, q);
+ }
+ view = na_s_allocate_view(CLASS_OF(self));
+
+ na_copy_flags(self, view);
+ GetNArrayView(view,na2);
+
+ na_alloc_shape((narray_t*)na2, ndim_new);
+
+ na2->stridx = ALLOC_N(stridx_t,ndim_new);
+
+ elmsz = nary_element_stride(self);
+
+ switch(na1->type) {
+ case NARRAY_DATA_T:
+ case NARRAY_FILEMAP_T:
+ na_index_aref_nadata((narray_data_t *)na1,na2,q,elmsz,ndim,keep_dim);
+ na2->data = self;
+ break;
+ case NARRAY_VIEW_T:
+ na2->offset = ((narray_view_t *)na1)->offset;
+ na2->data = ((narray_view_t *)na1)->data;
+ na_index_aref_naview((narray_view_t *)na1,na2,q,elmsz,ndim,keep_dim);
+ break;
+ }
+ if (store) {
+ na_get_pointer_for_write(store); // allocate memory
+ na_store(na_flatten_dim(store,0),view);
+ return store;
+ }
+ return view;
+}
+
+static VALUE
+na_aref_md_ensure(VALUE data_value)
+{
+ na_aref_md_data_t *data = (na_aref_md_data_t*)(data_value);
+ int i;
+ for (i=0; i<data->ndim; i++) {
+ xfree(data->q[i].idx);
+ }
+ xfree(data->q);
+ return Qnil;
+}
+
+VALUE
+na_aref_md(int argc, VALUE *argv, VALUE self, int keep_dim, int result_nd)
+{
+ VALUE args; // should be GC protected
+ narray_t *na1;
+ na_aref_md_data_t data;
+ VALUE store = 0;
+ VALUE idx;
+ narray_t *nidx;
+
+ GetNArray(self,na1);
+
+ args = rb_ary_new4(argc,argv);
+
+ if (argc == 1 && result_nd == 1) {
+ idx = argv[0];
+ if (rb_obj_is_kind_of(idx, rb_cArray)) {
+ idx = rb_apply(numo_cNArray,id_bracket,idx);
+ }
+ if (rb_obj_is_kind_of(idx, numo_cNArray)) {
+ GetNArray(idx,nidx);
+ if (NA_NDIM(nidx)>1) {
+ store = nary_new(CLASS_OF(self),NA_NDIM(nidx),NA_SHAPE(nidx));
+ idx = na_flatten(idx);
+ RARRAY_ASET(args,0,idx);
+ }
+ }
+ // flatten should be done only for narray-view with non-uniform stride.
+ if (na1->ndim > 1) {
+ self = na_flatten(self);
+ GetNArray(self,na1);
+ }
+ }
+
+ data.args = args;
+ data.self = self;
+ data.store = store;
+ data.ndim = result_nd;
+ data.q = na_allocate_index_args(result_nd);
+ data.na1 = na1;
+ data.keep_dim = keep_dim;
+
+ return rb_ensure(na_aref_md_protected, (VALUE)&data, na_aref_md_ensure, (VALUE)&data);
+}
+
+
+/* method: [](idx1,idx2,...,idxN) */
+VALUE
+na_aref_main(int nidx, VALUE *idx, VALUE self, int keep_dim, int nd)
+{
+ na_index_arg_to_internal_order(nidx, idx, self);
+
+ if (nidx==0) {
+ return rb_funcall(self,id_dup,0);
+ }
+ if (nidx==1) {
+ if (CLASS_OF(*idx)==numo_cBit) {
+ return rb_funcall(*idx,id_mask,1,self);
+ }
+ }
+ return na_aref_md(nidx, idx, self, keep_dim, nd);
+}
+
+
+/* method: slice(idx1,idx2,...,idxN) */
+static VALUE na_slice(int argc, VALUE *argv, VALUE self)
+{
+ int nd;
+ size_t pos;
+
+ nd = na_get_result_dimension(self, argc, argv, 0, &pos);
+ return na_aref_main(argc, argv, self, 1, nd);
+}
+
+
+static int
+check_index_count(int argc, int na_ndim, int count_new, int count_rest)
+{
+ int result_nd = na_ndim + count_new;
+
+ switch(count_rest) {
+ case 0:
+ if (count_new == 0 && argc == 1) return 1;
+ if (argc == result_nd) return result_nd;
+ rb_raise(rb_eIndexError,"# of index(=%i) should be "
+ "equal to ndim(=%i)",argc,na_ndim);
+ break;
+ case 1:
+ if (argc-1 <= result_nd) return result_nd;
+ rb_raise(rb_eIndexError,"# of index(=%i) > ndim(=%i) with :rest",
+ argc,na_ndim);
+ break;
+ }
+ return -1;
+}
+
+int
+na_get_result_dimension(VALUE self, int argc, VALUE *argv, ssize_t stride, size_t *pos_idx)
+{
+ int i, j;
+ int count_new=0;
+ int count_rest=0;
+ int count_else=0;
+ ssize_t x, s, m, pos, *idx;
+ narray_t *na;
+ narray_view_t *nv;
+ stridx_t sdx;
+ VALUE a;
+
+ GetNArray(self,na);
+ if (na->size == 0) {
+ rb_raise(rb_eRuntimeError, "cannot get index of empty array");
+ return -1;
+ }
+ idx = ALLOCA_N(ssize_t, argc);
+ for (i=j=0; i<argc; i++) {
+ a = argv[i];
+ switch(TYPE(a)) {
+ case T_FIXNUM:
+ idx[j++] = FIX2LONG(a);
+ break;
+ case T_BIGNUM:
+ case T_FLOAT:
+ idx[j++] = NUM2SSIZET(a);
+ break;
+ case T_FALSE:
+ case T_SYMBOL:
+ if (a==sym_rest || a==sym_tilde || a==Qfalse) {
+ argv[i] = Qfalse;
+ count_rest++;
+ break;
+ } else if (a==sym_new || a==sym_minus) {
+ argv[i] = sym_new;
+ count_new++;
+ }
+ // not break
+ default:
+ count_else++;
+ }
+ }
+
+ if (count_rest > 1) {
+ rb_raise(rb_eIndexError,"multiple rest-dimension is not allowd");
+ }
+ if (count_else != 0) {
+ return check_index_count(argc, na->ndim, count_new, count_rest);
+ }
+
+ switch(na->type) {
+ case NARRAY_VIEW_T:
+ GetNArrayView(self,nv);
+ pos = nv->offset;
+ if (j == na->ndim) {
+ for (i=j-1; i>=0; i--) {
+ x = na_range_check(idx[i], na->shape[i], i);
+ sdx = nv->stridx[i];
+ if (SDX_IS_INDEX(sdx)) {
+ pos += SDX_GET_INDEX(sdx)[x];
+ } else {
+ pos += SDX_GET_STRIDE(sdx)*x;
+ }
+ }
+ *pos_idx = pos;
+ }
+ else if (argc==1 && j==1) {
+ x = na_range_check(idx[0], na->size, 0);
+ for (i=na->ndim-1; i>=0; i--) {
+ s = na->shape[i];
+ m = x % s;
+ x = x / s;
+ sdx = nv->stridx[i];
+ if (SDX_IS_INDEX(sdx)) {
+ pos += SDX_GET_INDEX(sdx)[m];
+ } else {
+ pos += SDX_GET_STRIDE(sdx)*m;
+ }
+ }
+ *pos_idx = pos;
+ } else {
+ return check_index_count(argc, na->ndim, count_new, count_rest);
+ }
+ break;
+ default:
+ if (!stride) {
+ stride = nary_element_stride(self);
+ }
+ if (argc==1 && j==1) {
+ x = na_range_check(idx[0], na->size, 0);
+ *pos_idx = stride * x;
+ }
+ else if (j == na->ndim) {
+ pos = 0;
+ for (i=j-1; i>=0; i--) {
+ x = na_range_check(idx[i], na->shape[i], i);
+ pos += stride * x;
+ stride *= na->shape[i];
+ }
+ *pos_idx = pos;
+ } else {
+ return check_index_count(argc, na->ndim, count_new, count_rest);
+ }
+ }
+ return 0;
+}
+
+
+void
+Init_nary_index()
+{
+ rb_define_method(cNArray, "slice", na_slice, -1);
+
+ sym_ast = ID2SYM(rb_intern("*"));
+ sym_all = ID2SYM(rb_intern("all"));
+ sym_minus = ID2SYM(rb_intern("-"));
+ sym_new = ID2SYM(rb_intern("new"));
+ sym_reverse = ID2SYM(rb_intern("reverse"));
+ sym_plus = ID2SYM(rb_intern("+"));
+ //sym_reduce = ID2SYM(rb_intern("reduce"));
+ sym_sum = ID2SYM(rb_intern("sum"));
+ sym_tilde = ID2SYM(rb_intern("~"));
+ sym_rest = ID2SYM(rb_intern("rest"));
+ id_beg = rb_intern("begin");
+ id_end = rb_intern("end");
+ id_exclude_end = rb_intern("exclude_end?");
+ id_each = rb_intern("each");
+ id_step = rb_intern("step");
+ id_dup = rb_intern("dup");
+ id_bracket = rb_intern("[]");
+ id_shift_left = rb_intern("<<");
+ id_mask = rb_intern("mask");
+}
diff --git a/ext/numo/narray/math.c b/ext/numo/narray/math.c
new file mode 100644
index 0000000..ec5fda8
--- /dev/null
+++ b/ext/numo/narray/math.c
@@ -0,0 +1,147 @@
+/*
+ math.c
+ Numerical Array Extension for Ruby
+ (C) Copyright 1999-2017 by Masahiro TANAKA
+*/
+#include <ruby.h>
+#include "numo/narray.h"
+
+VALUE numo_mNMath;
+EXTERN VALUE numo_mDFloatMath, numo_mDComplexMath;
+EXTERN VALUE numo_mSFloatMath, numo_mSComplexMath;
+static ID id_send;
+static ID id_UPCAST;
+static ID id_DISPATCH;
+static ID id_extract;
+
+VALUE
+nary_type_s_upcast(VALUE type1, VALUE type2)
+{
+ VALUE upcast_hash;
+ VALUE result_type;
+
+ if (type1==type2) return type1;
+ upcast_hash = rb_const_get(type1, id_UPCAST);
+ result_type = rb_hash_aref(upcast_hash, type2);
+ if (NIL_P(result_type)) {
+ if (TYPE(type2)==T_CLASS) {
+ if ( RTEST(rb_class_inherited_p(type2,cNArray)) ) {
+ upcast_hash = rb_const_get(type2, id_UPCAST);
+ result_type = rb_hash_aref(upcast_hash, type1);
+ }
+ }
+ }
+ return result_type;
+}
+
+
+VALUE nary_math_cast2(VALUE type1, VALUE type2)
+{
+ if ( RTEST(rb_class_inherited_p( type1, cNArray )) ){
+ return nary_type_s_upcast( type1, type2 );
+ }
+ if ( RTEST(rb_class_inherited_p( type2, cNArray )) ){
+ return nary_type_s_upcast( type2, type1 );
+ }
+ if ( RTEST(rb_class_inherited_p( type1, rb_cNumeric )) &&
+ RTEST(rb_class_inherited_p( type2, rb_cNumeric )) ){
+ if ( RTEST(rb_class_inherited_p( type1, rb_cComplex)) ||
+ RTEST(rb_class_inherited_p( type2, rb_cComplex )) ){
+ return rb_cComplex;
+ }
+ return rb_cFloat;
+ }
+ return type2;
+}
+
+
+VALUE na_ary_composition_dtype(VALUE);
+
+VALUE nary_mathcast(int argc, VALUE *argv)
+{
+ VALUE type, type2;
+ int i;
+
+ type = na_ary_composition_dtype(argv[0]);
+ for (i=1; i<argc; i++) {
+ type2 = na_ary_composition_dtype(argv[i]);
+ type = nary_math_cast2(type, type2);
+ if (NIL_P(type)) {
+ rb_raise(rb_eTypeError,"includes unknown DataType for upcast");
+ }
+ }
+ return type;
+}
+
+
+/*
+ Dispatches method to Math module of upcasted type,
+ eg, Numo::DFloat::Math.
+ @overload method_missing(name,x,...)
+ @param [Symbol] name method name.
+ @param [NArray,Numeric] x input array.
+ @return [NArray] result.
+*/
+VALUE nary_math_method_missing(int argc, VALUE *argv, VALUE mod)
+{
+ VALUE type, ans, typemod, hash;
+ if (argc>1) {
+ type = nary_mathcast(argc-1,argv+1);
+
+ hash = rb_const_get(mod, id_DISPATCH);
+ typemod = rb_hash_aref( hash, type );
+ if (NIL_P(typemod)) {
+ rb_raise(rb_eTypeError,"%s is unknown for Numo::NMath",
+ rb_class2name(type));
+ }
+
+ ans = rb_funcall2(typemod,id_send,argc,argv);
+
+ if (!RTEST(rb_class_inherited_p(type,cNArray)) &&
+ IsNArray(ans) ) {
+ ans = rb_funcall(ans,id_extract,0);
+ }
+ return ans;
+ }
+ rb_raise(rb_eArgError,"argument or method missing");
+ return Qnil;
+}
+
+
+void
+Init_nary_math()
+{
+ VALUE hCast;
+
+ numo_mNMath = rb_define_module_under(mNumo, "NMath");
+ rb_define_singleton_method(numo_mNMath, "method_missing", nary_math_method_missing, -1);
+
+ hCast = rb_hash_new();
+ rb_define_const(numo_mNMath, "DISPATCH", hCast);
+ rb_hash_aset(hCast, numo_cInt64, numo_mDFloatMath);
+ rb_hash_aset(hCast, numo_cInt32, numo_mDFloatMath);
+ rb_hash_aset(hCast, numo_cInt16, numo_mDFloatMath);
+ rb_hash_aset(hCast, numo_cInt8, numo_mDFloatMath);
+ rb_hash_aset(hCast, numo_cUInt64, numo_mDFloatMath);
+ rb_hash_aset(hCast, numo_cUInt32, numo_mDFloatMath);
+ rb_hash_aset(hCast, numo_cUInt16, numo_mDFloatMath);
+ rb_hash_aset(hCast, numo_cUInt8, numo_mDFloatMath);
+ rb_hash_aset(hCast, numo_cDFloat, numo_mDFloatMath);
+ rb_hash_aset(hCast, numo_cDFloat, numo_mDFloatMath);
+ rb_hash_aset(hCast, numo_cDComplex, numo_mDComplexMath);
+ rb_hash_aset(hCast, numo_cSFloat, numo_mSFloatMath);
+ rb_hash_aset(hCast, numo_cSComplex, numo_mSComplexMath);
+#ifdef RUBY_INTEGER_UNIFICATION
+ rb_hash_aset(hCast, rb_cInteger, rb_mMath);
+#else
+ rb_hash_aset(hCast, rb_cFixnum, rb_mMath);
+ rb_hash_aset(hCast, rb_cBignum, rb_mMath);
+#endif
+ rb_hash_aset(hCast, rb_cFloat, rb_mMath);
+ rb_hash_aset(hCast, rb_cComplex, numo_mDComplexMath);
+
+ id_send = rb_intern("send");
+ id_UPCAST = rb_intern("UPCAST");
+ id_DISPATCH = rb_intern("DISPATCH");
+ id_extract = rb_intern("extract");
+}
diff --git a/ext/numo/narray/narray.c b/ext/numo/narray/narray.c
new file mode 100644
index 0000000..ab38812
--- /dev/null
+++ b/ext/numo/narray/narray.c
@@ -0,0 +1,1975 @@
+/*
+ narray.c
+ Numerical Array Extension for Ruby
+ (C) Copyright 1999-2017 by Masahiro TANAKA
+*/
+#define NARRAY_C
+#include <ruby.h>
+#include <assert.h>
+
+/* global variables within this module */
+VALUE numo_cNArray;
+VALUE rb_mNumo;
+VALUE nary_eCastError;
+VALUE nary_eShapeError;
+VALUE nary_eOperationError;
+VALUE nary_eDimensionError;
+
+static ID id_contiguous_stride;
+static ID id_allocate;
+static ID id_element_byte_size;
+static ID id_fill;
+static ID id_seq;
+static ID id_logseq;
+static ID id_eye;
+static ID id_UPCAST;
+static ID id_cast;
+static ID id_dup;
+static ID id_to_host;
+static ID id_bracket;
+static ID id_shift_left;
+static ID id_eq;
+static ID id_count_false;
+static ID id_axis;
+static ID id_nan;
+static ID id_keepdims;
+
+VALUE cPointer;
+
+VALUE sym_reduce;
+VALUE sym_option;
+VALUE sym_loop_opt;
+VALUE sym_init;
+
+VALUE na_cStep;
+#ifndef HAVE_RB_CCOMPLEX
+VALUE rb_cComplex;
+#endif
+
+int numo_na_inspect_rows=20;
+int numo_na_inspect_cols=80;
+
+void Init_nary_data();
+void Init_nary_ndloop();
+void Init_nary_step();
+void Init_nary_index();
+void Init_numo_bit();
+void Init_numo_int8();
+void Init_numo_int16();
+void Init_numo_int32();
+void Init_numo_int64();
+void Init_numo_uint8();
+void Init_numo_uint16();
+void Init_numo_uint32();
+void Init_numo_uint64();
+void Init_numo_sfloat();
+void Init_numo_scomplex();
+void Init_numo_dfloat();
+void Init_numo_dcomplex();
+void Init_numo_robject();
+void Init_nary_math();
+void Init_nary_rand();
+void Init_nary_array();
+void Init_nary_struct();
+
+const rb_data_type_t na_data_type = {
+ "Numo::NArray",
+ {0, 0, 0,}, 0, 0, 0,
+};
+#include "numo/narray.h"
+
+
+static void
+nary_debug_info_nadata(VALUE self)
+{
+ narray_data_t *na;
+ GetNArrayData(self,na);
+
+ printf(" ptr = 0x%"SZF"x\n", (size_t)(na->ptr));
+}
+
+
+static VALUE
+nary_debug_info_naview(VALUE self)
+{
+ int i;
+ narray_view_t *na;
+ size_t *idx;
+ size_t j;
+ GetNArrayView(self,na);
+
+ printf(" data = 0x%"SZF"x\n", (size_t)na->data);
+ printf(" offset = %"SZF"d\n", (size_t)na->offset);
+ printf(" stridx = 0x%"SZF"x\n", (size_t)na->stridx);
+
+ if (na->stridx) {
+ printf(" stridx = [");
+ for (i=0; i<na->base.ndim; i++) {
+ if (SDX_IS_INDEX(na->stridx[i])) {
+
+ idx = SDX_GET_INDEX(na->stridx[i]);
+ printf(" index[%d]=[", i);
+ for (j=0; j<na->base.shape[i]; j++) {
+ printf(" %"SZF"d", idx[j]);
+ }
+ printf(" ] ");
+
+ } else {
+ printf(" %"SZF"d", SDX_GET_STRIDE(na->stridx[i]));
+ }
+ }
+ printf(" ]\n");
+ }
+ return Qnil;
+}
+
+
+VALUE
+nary_debug_info(VALUE self)
+{
+ int i;
+ narray_t *na;
+ GetNArray(self,na);
+
+ printf("%s:\n",rb_class2name(CLASS_OF(self)));
+ printf(" id = 0x%"PRI_VALUE_PREFIX"x\n", self);
+ printf(" type = %d\n", na->type);
+ printf(" flag = [%d,%d]\n", na->flag[0], na->flag[1]);
+ printf(" size = %"SZF"d\n", na->size);
+ printf(" ndim = %d\n", na->ndim);
+ printf(" shape = 0x%"SZF"x\n", (size_t)na->shape);
+ if (na->shape) {
+ printf(" shape = [");
+ for (i=0;i<na->ndim;i++)
+ printf(" %"SZF"d", na->shape[i]);
+ printf(" ]\n");
+ }
+
+ switch(na->type) {
+ case NARRAY_DATA_T:
+ case NARRAY_FILEMAP_T:
+ nary_debug_info_nadata(self);
+ break;
+ case NARRAY_VIEW_T:
+ nary_debug_info_naview(self);
+ break;
+ }
+ return Qnil;
+}
+
+
+static size_t
+na_view_memsize(const void* ptr)
+{
+ int i;
+ size_t size = sizeof(narray_view_t);
+ const narray_view_t *na = ptr;
+
+ assert(na->base.type == NARRAY_VIEW_T);
+
+ if (na->stridx != NULL) {
+ for (i=0; i<na->base.ndim; i++) {
+ if (SDX_IS_INDEX(na->stridx[i])) {
+ size += sizeof(size_t) * na->base.shape[i];
+ }
+ }
+ size += sizeof(stridx_t) * na->base.ndim;
+ }
+ if (na->base.size > 0) {
+ if (na->base.shape != NULL && na->base.shape != &(na->base.size)) {
+ size += sizeof(size_t) * na->base.ndim;
+ }
+ }
+ return size;
+}
+
+static void
+na_view_free(void* ptr)
+{
+ int i;
+ narray_view_t *na = (narray_view_t*)ptr;
+
+ assert(na->base.type == NARRAY_VIEW_T);
+
+ if (na->stridx != NULL) {
+ for (i=0; i<na->base.ndim; i++) {
+ if (SDX_IS_INDEX(na->stridx[i])) {
+ xfree(SDX_GET_INDEX(na->stridx[i]));
+ }
+ }
+ xfree(na->stridx);
+ na->stridx = NULL;
+ }
+ if (na->base.size > 0) {
+ if (na->base.shape != NULL && na->base.shape != &(na->base.size)) {
+ xfree(na->base.shape);
+ na->base.shape = NULL;
+ }
+ }
+ xfree(na);
+}
+
+static void
+na_view_gc_mark(void* na)
+{
+ if (((narray_t*)na)->type == NARRAY_VIEW_T) {
+ rb_gc_mark(((narray_view_t*)na)->data);
+ }
+}
+
+const rb_data_type_t na_data_type_view = {
+ "Numo::NArrayView",
+ {na_view_gc_mark, na_view_free, na_view_memsize,},
+ &na_data_type, 0, 0,
+};
+
+VALUE
+na_s_allocate_view(VALUE klass)
+{
+ narray_view_t *na = ALLOC(narray_view_t);
+
+ na->base.ndim = 0;
+ na->base.type = NARRAY_VIEW_T;
+ na->base.flag[0] = NA_FL0_INIT;
+ na->base.flag[1] = NA_FL1_INIT;
+ na->base.size = 0;
+ na->base.shape = NULL;
+ na->base.reduce = INT2FIX(0);
+ na->data = Qnil;
+ na->offset = 0;
+ na->stridx = NULL;
+ return TypedData_Wrap_Struct(klass, &na_data_type_view, (void*)na);
+}
+
+
+//static const size_t zero=0;
+
+void
+na_array_to_internal_shape(VALUE self, VALUE ary, size_t *shape)
+{
+ size_t i, n, c, s;
+ ssize_t x;
+ VALUE v;
+ int flag = 0;
+
+ n = RARRAY_LEN(ary);
+
+ if (RTEST(self)) {
+ flag = TEST_COLUMN_MAJOR(self);
+ }
+ if (flag) {
+ c = n-1;
+ s = -1;
+ } else {
+ c = 0;
+ s = 1;
+ }
+ for (i=0; i<n; i++) {
+ v = RARRAY_AREF(ary,i);
+ x = NUM2SSIZET(v);
+ if (x < 0) {
+ rb_raise(rb_eArgError,"size must be non-negative");
+ }
+ shape[c] = x;
+ c += s;
+ }
+}
+
+
+
+void
+na_alloc_shape(narray_t *na, int ndim)
+{
+ na->ndim = ndim;
+ na->size = 0;
+ switch(ndim) {
+ case 0:
+ case 1:
+ na->shape = &(na->size);
+ break;
+ default:
+ if (ndim < 0) {
+ rb_raise(nary_eDimensionError,"ndim=%d is negative", ndim);
+ }
+ if (ndim > NA_MAX_DIMENSION) {
+ rb_raise(nary_eDimensionError,"ndim=%d is too many", ndim);
+ }
+ na->shape = ALLOC_N(size_t, ndim);
+ }
+}
+
+void
+na_setup_shape(narray_t *na, int ndim, size_t *shape)
+{
+ int i;
+ size_t size;
+
+ na_alloc_shape(na, ndim);
+
+ if (ndim==0) {
+ na->size = 1;
+ }
+ else if (ndim==1) {
+ na->size = shape[0];
+ }
+ else {
+ for (i=0, size=1; i<ndim; i++) {
+ na->shape[i] = shape[i];
+ size *= shape[i];
+ }
+ na->size = size;
+ }
+}
+
+static void
+na_setup(VALUE self, int ndim, size_t *shape)
+{
+ narray_t *na;
+ GetNArray(self,na);
+ na_setup_shape(na, ndim, shape);
+}
+
+
+/*
+ @overload initialize(shape)
+ @overload initialize(size0, size1, ...)
+ @param [Array] shape (array of sizes along each dimension)
+ @param [Integer] sizeN (size along Nth-dimension)
+ @return [Numo::NArray] unallocated narray.
+
+ Constructs an instance of NArray class using the given
+ and <i>shape</i> or <i>sizes</i>.
+ Note that NArray itself is an abstract super class and
+ not suitable to create instances.
+ Use Typed Subclasses of NArray (DFloat, Int32, etc) to create instances.
+ This method does not allocate memory for array data.
+ Memory is allocated on write method such as #fill, #store, #seq, etc.
+
+ @example
+ i = Numo::Int64.new([2,4,3])
+ #=> Numo::Int64#shape=[2,4,3](empty)
+
+ f = Numo::DFloat.new(3,4)
+ #=> Numo::DFloat#shape=[3,4](empty)
+
+ f.fill(2)
+ #=> Numo::DFloat#shape=[3,4]
+ # [[2, 2, 2, 2],
+ # [2, 2, 2, 2],
+ # [2, 2, 2, 2]]
+
+ x = Numo::NArray.new(5)
+ #=> in `new': allocator undefined for Numo::NArray (TypeError)
+ # from t.rb:9:in `<main>'
+
+*/
+static VALUE
+na_initialize(VALUE self, VALUE args)
+{
+ VALUE v;
+ size_t *shape=NULL;
+ int ndim;
+
+ if (RARRAY_LEN(args) == 1) {
+ v = RARRAY_AREF(args,0);
+ if (TYPE(v) != T_ARRAY) {
+ v = args;
+ }
+ } else {
+ v = args;
+ }
+ ndim = RARRAY_LEN(v);
+ if (ndim > NA_MAX_DIMENSION) {
+ rb_raise(rb_eArgError,"ndim=%d exceeds maximum dimension",ndim);
+ }
+ shape = ALLOCA_N(size_t, ndim);
+ // setup size_t shape[] from VALUE shape argument
+ na_array_to_internal_shape(self, v, shape);
+ na_setup(self, ndim, shape);
+
+ return self;
+}
+
+
+VALUE
+nary_new(VALUE klass, int ndim, size_t *shape)
+{
+ volatile VALUE obj;
+
+ obj = rb_funcall(klass, id_allocate, 0);
+ na_setup(obj, ndim, shape);
+ return obj;
+}
+
+
+VALUE
+nary_view_new(VALUE klass, int ndim, size_t *shape)
+{
+ volatile VALUE obj;
+
+ obj = na_s_allocate_view(klass);
+ na_setup(obj, ndim, shape);
+ return obj;
+}
+
+
+/*
+ Replaces the contents of self with the contents of other narray.
+ Used in dup and clone method.
+ @overload initialize_copy(other)
+ @param [Numo::NArray] other
+ @return [Numo::NArray] self
+ */
+static VALUE
+na_initialize_copy(VALUE self, VALUE orig)
+{
+ narray_t *na;
+ GetNArray(orig,na);
+
+ na_setup(self,NA_NDIM(na),NA_SHAPE(na));
+ na_store(self,orig);
+ na_copy_flags(orig,self);
+ return self;
+}
+
+
+/*
+ * call-seq:
+ * zeros(shape) => narray
+ * zeros(size1,size2,...) => narray
+ *
+ * Returns a zero-filled narray with <i>shape</i>.
+ * This singleton method is valid not for NArray class itself
+ * but for typed NArray subclasses, e.g., DFloat, Int64.
+ * @example
+ * a = Numo::DFloat.zeros(3,5)
+ * => Numo::DFloat#shape=[3,5]
+ * [[0, 0, 0, 0, 0],
+ * [0, 0, 0, 0, 0],
+ * [0, 0, 0, 0, 0]]
+ */
+static VALUE
+na_s_zeros(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE obj;
+ obj = rb_class_new_instance(argc, argv, klass);
+ return rb_funcall(obj, id_fill, 1, INT2FIX(0));
+}
+
+
+/*
+ * call-seq:
+ * ones(shape) => narray
+ * ones(size1,size2,...) => narray
+ *
+ * Returns a one-filled narray with <i>shape</i>.
+ * This singleton method is valid not for NArray class itself
+ * but for typed NArray subclasses, e.g., DFloat, Int64.
+ * @example
+ * a = Numo::DFloat.ones(3,5)
+ * => Numo::DFloat#shape=[3,5]
+ * [[1, 1, 1, 1, 1],
+ * [1, 1, 1, 1, 1],
+ * [1, 1, 1, 1, 1]]
+ */
+static VALUE
+na_s_ones(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE obj;
+ obj = rb_class_new_instance(argc, argv, klass);
+ return rb_funcall(obj, id_fill, 1, INT2FIX(1));
+}
+
+
+/*
+ Returns an array of N linearly spaced points between x1 and x2.
+ This singleton method is valid not for NArray class itself
+ but for typed NArray subclasses, e.g., DFloat, Int64.
+
+ @overload linspace(x1, x2, [n])
+ @param [Numeric] x1 The start value
+ @param [Numeric] x2 The end value
+ @param [Integer] n The number of elements. (default is 100).
+ @return [Numo::NArray] result array.
+
+ @example
+ a = Numo::DFloat.linspace(-5,5,7)
+ => Numo::DFloat#shape=[7]
+ [-5, -3.33333, -1.66667, 0, 1.66667, 3.33333, 5]
+ */
+static VALUE
+na_s_linspace(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE obj, vx1, vx2, vstep, vsize;
+ double n;
+ int narg;
+
+ narg = rb_scan_args(argc,argv,"21",&vx1,&vx2,&vsize);
+ if (narg==3) {
+ n = NUM2DBL(vsize);
+ } else {
+ n = 100;
+ vsize = INT2FIX(100);
+ }
+
+ obj = rb_funcall(vx2, '-', 1, vx1);
+ vstep = rb_funcall(obj, '/', 1, DBL2NUM(n-1));
+
+ obj = rb_class_new_instance(1, &vsize, klass);
+ return rb_funcall(obj, id_seq, 2, vx1, vstep);
+}
+
+/*
+ Returns an array of N logarithmically spaced points between 10^a and 10^b.
+ This singleton method is valid not for NArray having +logseq+ method,
+ i.e., DFloat, SFloat, DComplex, and SComplex.
+
+ @overload logspace(a, b, [n, base])
+ @param [Numeric] a The start value
+ @param [Numeric] b The end value
+ @param [Integer] n The number of elements. (default is 50)
+ @param [Numeric] base The base of log space. (default is 10)
+ @return [Numo::NArray] result array.
+
+ @example
+ Numo::DFloat.logspace(4,0,5,2)
+ => Numo::DFloat#shape=[5]
+ [16, 8, 4, 2, 1]
+ Numo::DComplex.logspace(0,1i*Math::PI,5,Math::E)
+ => Numo::DComplex#shape=[5]
+ [1+4.44659e-323i, 0.707107+0.707107i, 6.12323e-17+1i, -0.707107+0.707107i, ...]
+ */
+static VALUE
+na_s_logspace(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE obj, vx1, vx2, vstep, vsize, vbase;
+ double n;
+
+ rb_scan_args(argc,argv,"22",&vx1,&vx2,&vsize,&vbase);
+ if (vsize == Qnil) {
+ vsize = INT2FIX(50);
+ n = 50;
+ } else {
+ n = NUM2DBL(vsize);
+ }
+ if (vbase == Qnil) {
+ vbase = DBL2NUM(10);
+ }
+
+ obj = rb_funcall(vx2, '-', 1, vx1);
+ vstep = rb_funcall(obj, '/', 1, DBL2NUM(n-1));
+
+ obj = rb_class_new_instance(1, &vsize, klass);
+ return rb_funcall(obj, id_logseq, 3, vx1, vstep, vbase);
+}
+
+
+/*
+ Returns a NArray with shape=(n,n) whose diagonal elements are 1, otherwise 0.
+ @overload eye(n)
+ @param [Integer] n Size of NArray. Creates 2-D NArray with shape=(n,n)
+ @return [Numo::NArray] created NArray.
+ @example
+ a = Numo::DFloat.eye(3)
+ => Numo::DFloat#shape=[3,3]
+ [[1, 0, 0],
+ [0, 1, 0],
+ [0, 0, 1]]
+*/
+static VALUE
+na_s_eye(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE obj;
+ VALUE tmp[2];
+
+ if (argc==0) {
+ rb_raise(rb_eArgError,"No argument");
+ }
+ else if (argc==1) {
+ tmp[0] = tmp[1] = argv[0];
+ argv = tmp;
+ argc = 2;
+ }
+ obj = rb_class_new_instance(argc, argv, klass);
+ return rb_funcall(obj, id_eye, 0);
+}
+
+
+
+#define READ 1
+#define WRITE 2
+
+static char *
+na_get_pointer_for_rw(VALUE self, int flag)
+{
+ char *ptr;
+ VALUE obj;
+ narray_t *na;
+
+ if ((flag & WRITE) && OBJ_FROZEN(self)) {
+ rb_raise(rb_eRuntimeError, "cannot write to frozen NArray.");
+ }
+
+ GetNArray(self,na);
+
+ switch(NA_TYPE(na)) {
+ case NARRAY_DATA_T:
+ ptr = NA_DATA_PTR(na);
+ if (NA_SIZE(na) > 0 && ptr == NULL) {
+ if (flag & READ) {
+ rb_raise(rb_eRuntimeError,"cannot read unallocated NArray");
+ }
+ if (flag & WRITE) {
+ rb_funcall(self, id_allocate, 0);
+ ptr = NA_DATA_PTR(na);
+ }
+ }
+ return ptr;
+ case NARRAY_VIEW_T:
+ obj = NA_VIEW_DATA(na);
+ if ((flag & WRITE) && OBJ_FROZEN(obj)) {
+ rb_raise(rb_eRuntimeError, "cannot write to frozen NArray.");
+ }
+
+ if (flag & WRITE) {
+ if (OBJ_FROZEN(obj)) {
+ rb_raise(rb_eRuntimeError, "cannot write to frozen NArray.");
+ }
+ }
+ GetNArray(obj,na);
+ switch(NA_TYPE(na)) {
+ case NARRAY_DATA_T:
+ ptr = NA_DATA_PTR(na);
+ if (flag & (READ|WRITE)) {
+ if (NA_SIZE(na) > 0 && ptr == NULL) {
+ rb_raise(rb_eRuntimeError,"cannot read/write unallocated NArray");
+ }
+ }
+ return ptr;
+ default:
+ rb_raise(rb_eRuntimeError,"invalid NA_TYPE of view: %d",NA_TYPE(na));
+ }
+ default:
+ rb_raise(rb_eRuntimeError,"invalid NA_TYPE: %d",NA_TYPE(na));
+ }
+
+ return NULL;
+}
+
+char *
+na_get_pointer_for_read(VALUE self)
+{
+ return na_get_pointer_for_rw(self, READ);
+}
+
+char *
+na_get_pointer_for_write(VALUE self)
+{
+ return na_get_pointer_for_rw(self, WRITE);
+}
+
+char *
+na_get_pointer_for_read_write(VALUE self)
+{
+ return na_get_pointer_for_rw(self, READ|WRITE);
+}
+
+char *
+na_get_pointer(VALUE self)
+{
+ return na_get_pointer_for_rw(self, 0);
+}
+
+
+void
+na_release_lock(VALUE self)
+{
+ narray_t *na;
+
+ UNSET_LOCK(self);
+ GetNArray(self,na);
+
+ switch(NA_TYPE(na)) {
+ case NARRAY_VIEW_T:
+ na_release_lock(NA_VIEW_DATA(na));
+ break;
+ }
+}
+
+
+/* method: size() -- returns the total number of typeents */
+static VALUE
+na_size(VALUE self)
+{
+ narray_t *na;
+ GetNArray(self,na);
+ return SIZET2NUM(na->size);
+}
+
+
+/* method: size() -- returns the total number of typeents */
+static VALUE
+na_ndim(VALUE self)
+{
+ narray_t *na;
+ GetNArray(self,na);
+ return INT2NUM(na->ndim);
+}
+
+
+/*
+ Returns true if self.size == 0.
+ @overload empty?
+*/
+static VALUE
+na_empty_p(VALUE self)
+{
+ narray_t *na;
+ GetNArray(self,na);
+ if (NA_SIZE(na)==0) {
+ return Qtrue;
+ }
+ return Qfalse;
+}
+
+
+/* method: shape() -- returns shape, array of the size of dimensions */
+static VALUE
+ na_shape(VALUE self)
+{
+ volatile VALUE v;
+ narray_t *na;
+ size_t i, n, c, s;
+
+ GetNArray(self,na);
+ n = NA_NDIM(na);
+ if (TEST_COLUMN_MAJOR(self)) {
+ c = n-1;
+ s = -1;
+ } else {
+ c = 0;
+ s = 1;
+ }
+ v = rb_ary_new2(n);
+ for (i=0; i<n; i++) {
+ rb_ary_push(v, SIZET2NUM(na->shape[c]));
+ c += s;
+ }
+ return v;
+}
+
+
+unsigned int
+nary_element_stride(VALUE v)
+{
+ narray_type_info_t *info;
+ narray_t *na;
+
+ GetNArray(v,na);
+ if (na->type == NARRAY_VIEW_T) {
+ v = NA_VIEW_DATA(na);
+ GetNArray(v,na);
+ }
+ assert(na->type == NARRAY_DATA_T);
+
+ info = (narray_type_info_t *)(RTYPEDDATA_TYPE(v)->data);
+ return info->element_stride;
+}
+
+size_t
+na_dtype_elmsz(VALUE klass)
+{
+ return NUM2SIZET(rb_const_get(klass, id_contiguous_stride));
+}
+
+size_t
+na_get_offset(VALUE self)
+{
+ narray_t *na;
+ GetNArray(self,na);
+
+ switch(na->type) {
+ case NARRAY_DATA_T:
+ case NARRAY_FILEMAP_T:
+ return 0;
+ case NARRAY_VIEW_T:
+ return NA_VIEW_OFFSET(na);
+ }
+ return 0;
+}
+
+
+void
+na_index_arg_to_internal_order(int argc, VALUE *argv, VALUE self)
+{
+ int i,j;
+ VALUE tmp;
+
+ if (TEST_COLUMN_MAJOR(self)) {
+ for (i=0,j=argc-1; i<argc/2; i++,j--) {
+ tmp = argv[i];
+ argv[i] = argv[j];
+ argv[j] = tmp;
+ }
+ }
+}
+
+void
+na_copy_flags(VALUE src, VALUE dst)
+{
+ narray_t *na1, *na2;
+
+ GetNArray(src,na1);
+ GetNArray(dst,na2);
+
+ na2->flag[0] = na1->flag[0];
+ //na2->flag[1] = NA_FL1_INIT;
+
+ RBASIC(dst)->flags |= (RBASIC(src)->flags) &
+ (FL_USER1|FL_USER2|FL_USER3|FL_USER4|FL_USER5|FL_USER6|FL_USER7);
+}
+
+
+// fix name, ex, allow_stride_for_flatten_view
+VALUE
+na_check_ladder(VALUE self, int start_dim)
+{
+ int i;
+ ssize_t st0, st1;
+ narray_t *na;
+ GetNArray(self,na);
+
+ if (start_dim < -na->ndim || start_dim >= na->ndim) {
+ rb_bug("start_dim (%d) out of range",start_dim);
+ }
+
+ switch(na->type) {
+ case NARRAY_DATA_T:
+ case NARRAY_FILEMAP_T:
+ return Qtrue;
+ case NARRAY_VIEW_T:
+ // negative dim -> position from last dim
+ if (start_dim < 0) {
+ start_dim += NA_NDIM(na);
+ }
+ // not ladder if it has index
+ for (i=start_dim; i<NA_NDIM(na); i++) {
+ if (NA_IS_INDEX_AT(na,i))
+ return Qfalse;
+ }
+ // check stride
+ st0 = NA_STRIDE_AT(na,start_dim);
+ for (i=start_dim+1; i<NA_NDIM(na); i++) {
+ st1 = NA_STRIDE_AT(na,i);
+ if (st0 != (ssize_t)(st1 * NA_SHAPE(na)[i])) {
+ return Qfalse;
+ }
+ st0 = st1;
+ }
+ }
+ return Qtrue;
+}
+
+VALUE
+na_check_contiguous(VALUE self)
+{
+ ssize_t elmsz;
+ narray_t *na;
+ GetNArray(self,na);
+
+ switch(na->type) {
+ case NARRAY_DATA_T:
+ case NARRAY_FILEMAP_T:
+ return Qtrue;
+ case NARRAY_VIEW_T:
+ if (NA_VIEW_STRIDX(na)==0) {
+ return Qtrue;
+ }
+ if (na_check_ladder(self,0)==Qtrue) {
+ elmsz = nary_element_stride(self);
+ if (elmsz == NA_STRIDE_AT(na,NA_NDIM(na)-1)) {
+ return Qtrue;
+ }
+ }
+ }
+ return Qfalse;
+}
+
+//----------------------------------------------------------------------
+
+/*
+ * call-seq:
+ * narray.view => narray
+ *
+ * Return view of NArray
+ */
+VALUE
+na_make_view(VALUE self)
+{
+ int i, nd;
+ size_t j;
+ size_t *idx1, *idx2;
+ ssize_t stride;
+ narray_t *na;
+ narray_view_t *na1, *na2;
+ volatile VALUE view;
+
+ GetNArray(self,na);
+ nd = na->ndim;
+
+ view = na_s_allocate_view(CLASS_OF(self));
+
+ na_copy_flags(self, view);
+ GetNArrayView(view, na2);
+
+ na_setup_shape((narray_t*)na2, nd, na->shape);
+ na2->stridx = ALLOC_N(stridx_t,nd);
+
+ switch(na->type) {
+ case NARRAY_DATA_T:
+ case NARRAY_FILEMAP_T:
+ stride = nary_element_stride(self);
+ for (i=nd; i--;) {
+ SDX_SET_STRIDE(na2->stridx[i],stride);
+ stride *= na->shape[i];
+ }
+ na2->offset = 0;
+ na2->data = self;
+ break;
+ case NARRAY_VIEW_T:
+ GetNArrayView(self, na1);
+ for (i=0; i<nd; i++) {
+ if (SDX_IS_INDEX(na1->stridx[i])) {
+ idx1 = SDX_GET_INDEX(na1->stridx[i]);
+ idx2 = ALLOC_N(size_t,na1->base.shape[i]);
+ for (j=0; j<na1->base.shape[i]; j++) {
+ idx2[j] = idx1[j];
+ }
+ SDX_SET_INDEX(na2->stridx[i],idx2);
+ } else {
+ na2->stridx[i] = na1->stridx[i];
+ }
+ }
+ na2->offset = na1->offset;
+ na2->data = na1->data;
+ break;
+ }
+
+ return view;
+}
+
+
+//----------------------------------------------------------------------
+
+/*
+ * call-seq:
+ * narray.expand_dims(dim) => narray view
+ *
+ * Expand the shape of an array. Insert a new axis with size=1
+ * at a given dimension.
+ * @param [Integer] dim dimension at which new axis is inserted.
+ * @return [Numo::NArray] result narray view.
+ */
+VALUE
+na_expand_dims(VALUE self, VALUE vdim)
+{
+ int i, j, nd, dim;
+ size_t *shape, *na_shape;
+ stridx_t *stridx, *na_stridx;
+ narray_t *na;
+ narray_view_t *na2;
+ VALUE view;
+
+ GetNArray(self,na);
+ nd = na->ndim;
+
+ dim = NUM2INT(vdim);
+ if (dim < -nd-1 || dim > nd) {
+ rb_raise(nary_eDimensionError,"invalid axis (%d for %dD NArray)",
+ dim,nd);
+ }
+ if (dim < 0) {
+ dim += nd+1;
+ }
+
+ view = na_make_view(self);
+ GetNArrayView(view, na2);
+
+ shape = ALLOC_N(size_t,nd+1);
+ stridx = ALLOC_N(stridx_t,nd+1);
+ na_shape = na2->base.shape;
+ na_stridx = na2->stridx;
+
+ for (i=j=0; i<=nd; i++) {
+ if (i==dim) {
+ shape[i] = 1;
+ SDX_SET_STRIDE(stridx[i],0);
+ } else {
+ shape[i] = na_shape[j];
+ stridx[i] = na_stridx[j];
+ j++;
+ }
+ }
+
+ na2->stridx = stridx;
+ xfree(na_stridx);
+ na2->base.shape = shape;
+ if (na_shape != &(na2->base.size)) {
+ xfree(na_shape);
+ }
+ na2->base.ndim++;
+ return view;
+}
+
+//----------------------------------------------------------------------
+
+/*
+ * call-seq:
+ * narray.reverse([dim0,dim1,..]) => narray
+ *
+ * Return reversed view along specified dimeinsion
+ */
+VALUE
+nary_reverse(int argc, VALUE *argv, VALUE self)
+{
+ int i, nd;
+ size_t j, n;
+ size_t offset;
+ size_t *idx1, *idx2;
+ ssize_t stride;
+ ssize_t sign;
+ narray_t *na;
+ narray_view_t *na1, *na2;
+ VALUE view;
+ VALUE reduce;
+
+ reduce = na_reduce_dimension(argc, argv, 1, &self, 0, 0);
+
+ GetNArray(self,na);
+ nd = na->ndim;
+
+ view = na_s_allocate_view(CLASS_OF(self));
+
+ na_copy_flags(self, view);
+ GetNArrayView(view, na2);
+
+ na_setup_shape((narray_t*)na2, nd, na->shape);
+ na2->stridx = ALLOC_N(stridx_t,nd);
+
+ switch(na->type) {
+ case NARRAY_DATA_T:
+ case NARRAY_FILEMAP_T:
+ stride = nary_element_stride(self);
+ offset = 0;
+ for (i=nd; i--;) {
+ if (na_test_reduce(reduce,i)) {
+ offset += (na->shape[i]-1)*stride;
+ sign = -1;
+ } else {
+ sign = 1;
+ }
+ SDX_SET_STRIDE(na2->stridx[i],stride*sign);
+ stride *= na->shape[i];
+ }
+ na2->offset = offset;
+ na2->data = self;
+ break;
+ case NARRAY_VIEW_T:
+ GetNArrayView(self, na1);
+ offset = na1->offset;
+ for (i=0; i<nd; i++) {
+ n = na1->base.shape[i];
+ if (SDX_IS_INDEX(na1->stridx[i])) {
+ idx1 = SDX_GET_INDEX(na1->stridx[i]);
+ idx2 = ALLOC_N(size_t,n);
+ if (na_test_reduce(reduce,i)) {
+ for (j=0; j<n; j++) {
+ idx2[n-1-j] = idx1[j];
+ }
+ } else {
+ for (j=0; j<n; j++) {
+ idx2[j] = idx1[j];
+ }
+ }
+ SDX_SET_INDEX(na2->stridx[i],idx2);
+ } else {
+ stride = SDX_GET_STRIDE(na1->stridx[i]);
+ if (na_test_reduce(reduce,i)) {
+ offset += (n-1)*stride;
+ SDX_SET_STRIDE(na2->stridx[i],-stride);
+ } else {
+ na2->stridx[i] = na1->stridx[i];
+ }
+ }
+ }
+ na2->offset = offset;
+ na2->data = na1->data;
+ break;
+ }
+
+ return view;
+}
+
+//----------------------------------------------------------------------
+
+VALUE
+numo_na_upcast(VALUE type1, VALUE type2)
+{
+ VALUE upcast_hash;
+ VALUE result_type;
+
+ if (type1==type2) {
+ return type1;
+ }
+ upcast_hash = rb_const_get(type1, id_UPCAST);
+ result_type = rb_hash_aref(upcast_hash, type2);
+ if (NIL_P(result_type)) {
+ if (TYPE(type2)==T_CLASS) {
+ if (RTEST(rb_class_inherited_p(type2,cNArray))) {
+ upcast_hash = rb_const_get(type2, id_UPCAST);
+ result_type = rb_hash_aref(upcast_hash, type1);
+ }
+ }
+ }
+ return result_type;
+}
+
+/*
+ Returns an array containing other and self,
+ both are converted to upcasted type of NArray.
+ Note that NArray has distinct UPCAST mechanism.
+ Coerce is used for operation between non-NArray and NArray.
+ @overload coerce(other)
+ @param [Object] other numeric object.
+ @return [Array] NArray-casted [other,self]
+*/
+static VALUE
+nary_coerce(VALUE x, VALUE y)
+{
+ VALUE type;
+
+ type = numo_na_upcast(CLASS_OF(x), CLASS_OF(y));
+ y = rb_funcall(type,id_cast,1,y);
+ return rb_assoc_new(y , x);
+}
+
+
+/*
+ Returns total byte size of NArray.
+ @return [Integer] byte size.
+ */
+static VALUE
+nary_byte_size(VALUE self)
+{
+ VALUE velmsz;
+ narray_t *na;
+
+ GetNArray(self,na);
+ velmsz = rb_const_get(CLASS_OF(self), id_element_byte_size);
+ if (FIXNUM_P(velmsz)) {
+ return SIZET2NUM(NUM2SIZET(velmsz) * na->size);
+ }
+ return SIZET2NUM(ceil(NUM2DBL(velmsz) * na->size));
+}
+
+/*
+ Returns byte size of one element of NArray.
+ @return [Numeric] byte size.
+ */
+static VALUE
+nary_s_byte_size(VALUE type)
+{
+ return rb_const_get(type, id_element_byte_size);
+}
+
+
+/*
+ Returns a new 1-D array initialized from binary raw data in a string.
+ @overload from_binary(string,[shape])
+ @param [String] string Binary raw data.
+ @param [Array] shape array of integers representing array shape.
+ @return [Numo::NArray] NArray containing binary data.
+ */
+static VALUE
+nary_s_from_binary(int argc, VALUE *argv, VALUE type)
+{
+ size_t len, str_len, byte_size;
+ size_t *shape;
+ char *ptr;
+ int i, nd, narg;
+ VALUE vstr, vshape, vna;
+ VALUE velmsz;
+
+ narg = rb_scan_args(argc,argv,"11",&vstr,&vshape);
+ Check_Type(vstr,T_STRING);
+ str_len = RSTRING_LEN(vstr);
+ velmsz = rb_const_get(type, id_element_byte_size);
+ if (narg==2) {
+ switch(TYPE(vshape)) {
+ case T_FIXNUM:
+ nd = 1;
+ len = NUM2SIZET(vshape);
+ shape = &len;
+ break;
+ case T_ARRAY:
+ nd = RARRAY_LEN(vshape);
+ if (nd == 0 || nd > NA_MAX_DIMENSION) {
+ rb_raise(nary_eDimensionError,"too long or empty shape (%d)", nd);
+ }
+ shape = ALLOCA_N(size_t,nd);
+ len = 1;
+ for (i=0; i<nd; ++i) {
+ len *= shape[i] = NUM2SIZET(RARRAY_AREF(vshape,i));
+ }
+ break;
+ default:
+ rb_raise(rb_eArgError,"second argument must be size or shape");
+ }
+ if (FIXNUM_P(velmsz)) {
+ byte_size = len * NUM2SIZET(velmsz);
+ } else {
+ byte_size = ceil(len * NUM2DBL(velmsz));
+ }
+ if (byte_size > str_len) {
+ rb_raise(rb_eArgError, "specified size is too large");
+ }
+ } else {
+ nd = 1;
+ if (FIXNUM_P(velmsz)) {
+ len = str_len / NUM2SIZET(velmsz);
+ byte_size = len * NUM2SIZET(velmsz);
+ } else {
+ len = floor(str_len / NUM2DBL(velmsz));
+ byte_size = str_len;
+ }
+ if (len == 0) {
+ rb_raise(rb_eArgError, "string is empty or too short");
+ }
+ shape = ALLOCA_N(size_t,nd);
+ shape[0] = len;
+ }
+
+ vna = nary_new(type, nd, shape);
+ ptr = na_get_pointer_for_write(vna);
+
+ memcpy(ptr, RSTRING_PTR(vstr), byte_size);
+
+ return vna;
+}
+
+/*
+ Returns a new 1-D array initialized from binary raw data in a string.
+ @overload store_binary(string,[offset])
+ @param [String] string Binary raw data.
+ @param [Integer] (optional) offset Byte offset in string.
+ @return [Integer] stored length.
+ */
+static VALUE
+nary_store_binary(int argc, VALUE *argv, VALUE self)
+{
+ size_t size, str_len, byte_size, offset;
+ char *ptr;
+ int narg;
+ VALUE vstr, voffset;
+ VALUE velmsz;
+ narray_t *na;
+
+ narg = rb_scan_args(argc,argv,"11",&vstr,&voffset);
+ str_len = RSTRING_LEN(vstr);
+ if (narg==2) {
+ offset = NUM2SIZET(voffset);
+ if (str_len < offset) {
+ rb_raise(rb_eArgError, "offset is larger than string length");
+ }
+ str_len -= offset;
+ } else {
+ offset = 0;
+ }
+
+ GetNArray(self,na);
+ size = NA_SIZE(na);
+ velmsz = rb_const_get(CLASS_OF(self), id_element_byte_size);
+ if (FIXNUM_P(velmsz)) {
+ byte_size = size * NUM2SIZET(velmsz);
+ } else {
+ byte_size = ceil(size * NUM2DBL(velmsz));
+ }
+ if (byte_size > str_len) {
+ rb_raise(rb_eArgError, "string is too short to store");
+ }
+
+ ptr = na_get_pointer_for_write(self);
+ memcpy(ptr, RSTRING_PTR(vstr)+offset, byte_size);
+
+ return SIZET2NUM(byte_size);
+}
+
+/*
+ Returns string containing the raw data bytes in NArray.
+ @overload to_binary()
+ @return [String] String object containing binary raw data.
+ */
+static VALUE
+nary_to_binary(VALUE self)
+{
+ size_t len, offset=0;
+ char *ptr;
+ VALUE str;
+ narray_t *na;
+
+ GetNArray(self,na);
+ if (na->type == NARRAY_VIEW_T) {
+ if (na_check_contiguous(self)==Qtrue) {
+ offset = NA_VIEW_OFFSET(na);
+ } else {
+ self = rb_funcall(self,id_dup,0);
+ }
+ }
+ len = NUM2SIZET(nary_byte_size(self));
+ ptr = na_get_pointer_for_read(self);
+ str = rb_usascii_str_new(ptr+offset,len);
+ RB_GC_GUARD(self);
+ return str;
+}
+
+/*
+ Dump marshal data.
+ @overload marshal_dump()
+ @return [Array] Array containing marshal data.
+ */
+static VALUE
+nary_marshal_dump(VALUE self)
+{
+ VALUE a;
+
+ a = rb_ary_new();
+ rb_ary_push(a, INT2FIX(1)); // version
+ rb_ary_push(a, na_shape(self));
+ rb_ary_push(a, INT2FIX(NA_FLAG0(self)));
+ if (CLASS_OF(self) == numo_cRObject) {
+ narray_t *na;
+ VALUE *ptr;
+ size_t offset=0;
+ GetNArray(self,na);
+ if (na->type == NARRAY_VIEW_T) {
+ if (na_check_contiguous(self)==Qtrue) {
+ offset = NA_VIEW_OFFSET(na);
+ } else {
+ self = rb_funcall(self,id_dup,0);
+ }
+ }
+ ptr = (VALUE*)na_get_pointer_for_read(self);
+ rb_ary_push(a, rb_ary_new4(NA_SIZE(na), ptr+offset));
+ } else {
+ rb_ary_push(a, nary_to_binary(self));
+ }
+ RB_GC_GUARD(self);
+ return a;
+}
+
+VALUE na_inplace( VALUE self );
+/*
+ Load marshal data.
+ @overload marshal_load(data)
+ @params [Array] Array containing marshal data.
+ @return [nil]
+ */
+static VALUE
+nary_marshal_load(VALUE self, VALUE a)
+{
+ VALUE v;
+
+ if (TYPE(a) != T_ARRAY) {
+ rb_raise(rb_eArgError,"marshal argument should be array");
+ }
+ if (RARRAY_LEN(a) != 4) {
+ rb_raise(rb_eArgError,"marshal array size should be 4");
+ }
+ if (RARRAY_AREF(a,0) != INT2FIX(1)) {
+ rb_raise(rb_eArgError,"NArray marshal version %d is not supported "
+ "(only version 1)", NUM2INT(RARRAY_AREF(a,0)));
+ }
+ na_initialize(self,RARRAY_AREF(a,1));
+ NA_FL0_SET(self,FIX2INT(RARRAY_AREF(a,2)));
+ v = RARRAY_AREF(a,3);
+ if (CLASS_OF(self) == numo_cRObject) {
+ narray_t *na;
+ char *ptr;
+ if (TYPE(v) != T_ARRAY) {
+ rb_raise(rb_eArgError,"RObject content should be array");
+ }
+ GetNArray(self,na);
+ if (RARRAY_LEN(v) != (long)NA_SIZE(na)) {
+ rb_raise(rb_eArgError,"RObject content size mismatch");
+ }
+ ptr = na_get_pointer_for_write(self);
+ memcpy(ptr, RARRAY_PTR(v), NA_SIZE(na)*sizeof(VALUE));
+ } else {
+ nary_store_binary(1,&v,self);
+ if (TEST_BYTE_SWAPPED(self)) {
+ rb_funcall(na_inplace(self),id_to_host,0);
+ REVERSE_ENDIAN(self); // correct behavior??
+ }
+ }
+ RB_GC_GUARD(a);
+ return self;
+}
+
+
+/*
+ Cast self to another NArray datatype.
+ @overload cast_to(datatype)
+ @param [Class] datatype NArray datatype.
+ @return [Numo::NArray]
+ */
+static VALUE
+nary_cast_to(VALUE obj, VALUE type)
+{
+ return rb_funcall(type, id_cast, 1, obj);
+}
+
+
+
+bool
+na_test_reduce(VALUE reduce, int dim)
+{
+ size_t m;
+
+ if (!RTEST(reduce))
+ return 0;
+ if (FIXNUM_P(reduce)) {
+ m = FIX2LONG(reduce);
+ if (m==0) return 1;
+ return (m & (1u<<dim)) ? 1 : 0;
+ } else {
+ return (rb_funcall(reduce,id_bracket,1,INT2FIX(dim))==INT2FIX(1)) ?
+ 1 : 0 ;
+ }
+}
+
+
+static VALUE
+na_get_reduce_flag_from_narray(int naryc, VALUE *naryv, int *max_arg)
+{
+ int ndim, ndim0;
+ int rowmaj;
+ int i;
+ size_t j;
+ narray_t *na;
+ VALUE reduce;
+
+ if (naryc<1) {
+ rb_raise(rb_eRuntimeError,"must be positive: naryc=%d", naryc);
+ }
+ GetNArray(naryv[0],na);
+ if (na->size==0) {
+ rb_raise(nary_eShapeError,"cannot reduce empty NArray");
+ }
+ reduce = na->reduce;
+ ndim = ndim0 = na->ndim;
+ if (max_arg) *max_arg = 0;
+ rowmaj = TEST_COLUMN_MAJOR(naryv[0]);
+ for (i=0; i<naryc; i++) {
+ GetNArray(naryv[i],na);
+ if (na->size==0) {
+ rb_raise(nary_eShapeError,"cannot reduce empty NArray");
+ }
+ if (TEST_COLUMN_MAJOR(naryv[i]) != rowmaj) {
+ rb_raise(nary_eDimensionError,"dimension order is different");
+ }
+ if (na->ndim > ndim) { // maximum dimension
+ ndim = na->ndim;
+ if (max_arg) *max_arg = i;
+ }
+ }
+ if (ndim != ndim0) {
+ j = NUM2SIZET(reduce) << (ndim-ndim0);
+ reduce = SIZET2NUM(j);
+ }
+ return reduce;
+}
+
+
+static VALUE
+na_get_reduce_flag_from_axes(VALUE na_obj, VALUE axes)
+{
+ int i, r;
+ int ndim, rowmaj;
+ long narg;
+ size_t j;
+ size_t len;
+ ssize_t beg, step;
+ VALUE v;
+ size_t m;
+ VALUE reduce;
+ narray_t *na;
+
+ GetNArray(na_obj,na);
+ ndim = na->ndim;
+ rowmaj = TEST_COLUMN_MAJOR(na_obj);
+
+ m = 0;
+ reduce = Qnil;
+ narg = RARRAY_LEN(axes);
+ for (i=0; i<narg; i++) {
+ v = RARRAY_AREF(axes,i);
+ //printf("argv[%d]=",i);rb_p(v);
+ if (TYPE(v)==T_FIXNUM) {
+ beg = FIX2INT(v);
+ if (beg<0) beg+=ndim;
+ if (beg>=ndim || beg<0) {
+ rb_raise(nary_eDimensionError,"dimension is out of range");
+ }
+ len = 1;
+ step = 0;
+ //printf("beg=%d step=%d len=%d\n",beg,step,len);
+ } else if (rb_obj_is_kind_of(v,rb_cRange) ||
+ rb_obj_is_kind_of(v,na_cStep)) {
+ nary_step_array_index( v, ndim, &len, &beg, &step );
+ } else {
+ rb_raise(nary_eDimensionError, "invalid dimension argument %s",
+ rb_obj_classname(v));
+ }
+ for (j=0; j<len; j++) {
+ r = beg + step*j;
+ if (rowmaj) {
+ r = ndim-1-r;
+ }
+ if (reduce==Qnil) {
+ if ( r < (ssize_t)sizeof(size_t) ) {
+ m |= ((size_t)1) << r;
+ continue;
+ } else {
+ reduce = SIZET2NUM(m);
+ }
+ }
+ v = rb_funcall( INT2FIX(1), id_shift_left, 1, INT2FIX(r) );
+ reduce = rb_funcall( reduce, '|', 1, v );
+ }
+ }
+ if (NIL_P(reduce)) reduce = SIZET2NUM(m);
+ return reduce;
+}
+
+
+VALUE
+nary_reduce_options(VALUE axes, VALUE *opts, int naryc, VALUE *naryv,
+ ndfunc_t *ndf)
+{
+ int max_arg;
+ VALUE reduce;
+
+ // option: axis
+ if (opts[0] != Qundef && RTEST(opts[0])) {
+ if (!NIL_P(axes)) {
+ rb_raise(rb_eArgError,
+ "cannot specify axis-arguments and axis-keyword simultaneously");
+ }
+ if (TYPE(opts[0]) == T_ARRAY) {
+ axes = opts[0];
+ } else {
+ axes = rb_ary_new3(1,opts[0]);
+ }
+ }
+ if (ndf) {
+ // option: keepdims
+ if (opts[1] != Qundef) {
+ if (RTEST(opts[1]))
+ ndf->flag |= NDF_KEEP_DIM;
+ }
+ }
+
+ reduce = na_get_reduce_flag_from_narray(naryc, naryv, &max_arg);
+
+ if (NIL_P(axes)) return reduce;
+
+ return na_get_reduce_flag_from_axes(naryv[max_arg], axes);
+}
+
+
+VALUE
+nary_reduce_dimension(int argc, VALUE *argv, int naryc, VALUE *naryv,
+ ndfunc_t *ndf, na_iter_func_t iter_nan)
+{
+ long narg;
+ VALUE axes;
+ VALUE kw_hash = Qnil;
+ ID kw_table[3] = {id_axis,id_keepdims,id_nan};
+ VALUE opts[3] = {Qundef,Qundef,Qundef};
+
+ narg = rb_scan_args(argc, argv, "*:", &axes, &kw_hash);
+ rb_get_kwargs(kw_hash, kw_table, 0, 3, opts);
+
+ if (ndf) {
+ // option: nan
+ if (iter_nan && opts[2] != Qundef) {
+ if (RTEST(opts[2]))
+ ndf->func = iter_nan; // replace to nan-aware iterator function
+ }
+ }
+
+ return na_reduce_options((narg)?axes:Qnil, opts, naryc, naryv, ndf);
+}
+
+/*
+ Return true if column major.
+*/
+VALUE na_column_major_p( VALUE self )
+{
+ if (TEST_COLUMN_MAJOR(self))
+ return Qtrue;
+ else
+ return Qfalse;
+}
+
+/*
+ Return true if row major.
+*/
+VALUE na_row_major_p( VALUE self )
+{
+ if (TEST_ROW_MAJOR(self))
+ return Qtrue;
+ else
+ return Qfalse;
+}
+
+
+/*
+ Return true if byte swapped.
+*/
+VALUE na_byte_swapped_p( VALUE self )
+{
+ if (TEST_BYTE_SWAPPED(self))
+ return Qtrue;
+ return Qfalse;
+}
+
+/*
+ Return true if not byte swapped.
+*/
+VALUE na_host_order_p( VALUE self )
+{
+ if (TEST_BYTE_SWAPPED(self))
+ return Qfalse;
+ return Qtrue;
+}
+
+
+/*
+ Returns view of narray with inplace flagged.
+ @return [Numo::NArray] view of narray with inplace flag.
+*/
+VALUE na_inplace( VALUE self )
+{
+ VALUE view = self;
+ view = na_make_view(self);
+ SET_INPLACE(view);
+ return view;
+}
+
+/*
+ Set inplace flag to self.
+ @return [Numo::NArray] self
+*/
+VALUE na_inplace_bang( VALUE self )
+{
+ SET_INPLACE(self);
+ return self;
+}
+
+VALUE na_inplace_store( VALUE self, VALUE val )
+{
+ if (self==val)
+ return self;
+ else
+ return na_store( self, val );
+}
+
+/*
+ Return true if inplace flagged.
+*/
+VALUE na_inplace_p( VALUE self )
+{
+ if (TEST_INPLACE(self))
+ return Qtrue;
+ else
+ return Qfalse;
+}
+
+/*
+ Unset inplace flag to self.
+ @return [Numo::NArray] self
+*/
+VALUE na_out_of_place_bang( VALUE self )
+{
+ UNSET_INPLACE(self);
+ return self;
+}
+
+int na_debug_flag=0;
+
+static VALUE na_debug_set(VALUE mod, VALUE flag)
+{
+ na_debug_flag = RTEST(flag);
+ return Qnil;
+}
+
+static double na_profile_value=0;
+
+static VALUE na_profile(VALUE mod)
+{
+ return rb_float_new(na_profile_value);
+}
+
+static VALUE na_profile_set(VALUE mod, VALUE val)
+{
+ na_profile_value = NUM2DBL(val);
+ return val;
+}
+
+
+/*
+ Returns the number of rows used for NArray#inspect
+ @overload inspect_rows
+ @return [Integer or nil] the number of rows.
+*/
+static VALUE na_inspect_rows(VALUE mod)
+{
+ if (numo_na_inspect_rows > 0) {
+ return INT2NUM(numo_na_inspect_rows);
+ } else {
+ return Qnil;
+ }
+}
+
+/*
+ Set the number of rows used for NArray#inspect
+ @overload inspect_rows=(rows)
+ @param [Integer or nil] rows the number of rows
+ @return [nil]
+*/
+static VALUE na_inspect_rows_set(VALUE mod, VALUE num)
+{
+ if (RTEST(num)) {
+ numo_na_inspect_rows = NUM2INT(num);
+ } else {
+ numo_na_inspect_rows = 0;
+ }
+ return Qnil;
+}
+
+/*
+ Returns the number of cols used for NArray#inspect
+ @overload inspect_cols
+ @return [Integer or nil] the number of cols.
+*/
+static VALUE na_inspect_cols(VALUE mod)
+{
+ if (numo_na_inspect_cols > 0) {
+ return INT2NUM(numo_na_inspect_cols);
+ } else {
+ return Qnil;
+ }
+}
+
+/*
+ Set the number of cols used for NArray#inspect
+ @overload inspect_cols=(cols)
+ @param [Integer or nil] cols the number of cols
+ @return [nil]
+*/
+static VALUE na_inspect_cols_set(VALUE mod, VALUE num)
+{
+ if (RTEST(num)) {
+ numo_na_inspect_cols = NUM2INT(num);
+ } else {
+ numo_na_inspect_cols = 0;
+ }
+ return Qnil;
+}
+
+
+/*
+ Equality of self and other in view of numerical array.
+ i.e., both arrays have same shape and corresponding elements are equal.
+ @overload == other
+ @param [Object] other
+ @return [Boolean] true if self and other is equal.
+*/
+VALUE
+na_equal(VALUE self, volatile VALUE other)
+{
+ volatile VALUE vbool;
+ narray_t *na1, *na2;
+ int i;
+
+ GetNArray(self,na1);
+
+ if (!rb_obj_is_kind_of(other,cNArray)) {
+ other = rb_funcall(CLASS_OF(self), id_cast, 1, other);
+ }
+
+ GetNArray(other,na2);
+ if (na1->ndim != na2->ndim) {
+ return Qfalse;
+ }
+ for (i=0; i<na1->ndim; i++) {
+ if (na1->shape[i] != na2->shape[i]) {
+ return Qfalse;
+ }
+ }
+ vbool = rb_funcall(self, id_eq, 1, other);
+ return (rb_funcall(vbool, id_count_false, 0)==INT2FIX(0)) ? Qtrue : Qfalse;
+}
+
+
+
+/* initialization of NArray Class */
+void
+Init_narray()
+{
+ mNumo = rb_define_module("Numo");
+
+ /*
+ Document-class: Numo::NArray
+
+ Numo::NArray is the abstract super class for
+ Numerical N-dimensional Array in the Ruby/Numo module.
+ Use Typed Subclasses of NArray (Numo::DFloat, Int32, etc)
+ to create data array instances.
+ */
+ cNArray = rb_define_class_under(mNumo, "NArray", rb_cObject);
+
+#ifndef HAVE_RB_CCOMPLEX
+ rb_require("complex");
+ rb_cComplex = rb_const_get(rb_cObject, rb_intern("Complex"));
+#endif
+
+ rb_define_const(cNArray, "VERSION", rb_str_new2(NARRAY_VERSION));
+
+ nary_eCastError = rb_define_class_under(cNArray, "CastError", rb_eStandardError);
+ nary_eShapeError = rb_define_class_under(cNArray, "ShapeError", rb_eStandardError);
+ nary_eOperationError = rb_define_class_under(cNArray, "OperationError", rb_eStandardError);
+ nary_eDimensionError = rb_define_class_under(cNArray, "DimensionError", rb_eStandardError);
+
+ rb_define_singleton_method(cNArray, "debug=", na_debug_set, 1);
+ rb_define_singleton_method(cNArray, "profile", na_profile, 0);
+ rb_define_singleton_method(cNArray, "profile=", na_profile_set, 1);
+
+ rb_define_singleton_method(cNArray, "inspect_rows", na_inspect_rows, 0);
+ rb_define_singleton_method(cNArray, "inspect_rows=", na_inspect_rows_set, 1);
+ rb_define_singleton_method(cNArray, "inspect_cols", na_inspect_cols, 0);
+ rb_define_singleton_method(cNArray, "inspect_cols=", na_inspect_cols_set, 1);
+
+ /* Ruby allocation framework */
+ rb_undef_alloc_func(cNArray);
+ rb_define_method(cNArray, "initialize", na_initialize, -2);
+ rb_define_method(cNArray, "initialize_copy", na_initialize_copy, 1);
+
+ rb_define_singleton_method(cNArray, "zeros", na_s_zeros, -1);
+ rb_define_singleton_method(cNArray, "ones", na_s_ones, -1);
+ rb_define_singleton_method(cNArray, "linspace", na_s_linspace, -1);
+ rb_define_singleton_method(cNArray, "logspace", na_s_logspace, -1);
+ rb_define_singleton_method(cNArray, "eye", na_s_eye, -1);
+
+ rb_define_method(cNArray, "size", na_size, 0);
+ rb_define_alias (cNArray, "length","size");
+ rb_define_alias (cNArray, "total","size");
+ rb_define_method(cNArray, "shape", na_shape, 0);
+ rb_define_method(cNArray, "ndim", na_ndim,0);
+ rb_define_alias (cNArray, "rank","ndim");
+ rb_define_method(cNArray, "empty?", na_empty_p, 0);
+
+ rb_define_method(cNArray, "debug_info", nary_debug_info, 0);
+
+ rb_define_method(cNArray, "contiguous?", na_check_contiguous, 0);
+
+ rb_define_method(cNArray, "view", na_make_view, 0);
+ rb_define_method(cNArray, "expand_dims", na_expand_dims, 1);
+ rb_define_method(cNArray, "reverse", nary_reverse, -1);
+
+ rb_define_singleton_method(cNArray, "upcast", numo_na_upcast, 1);
+ rb_define_singleton_method(cNArray, "byte_size", nary_s_byte_size, 0);
+
+ rb_define_singleton_method(cNArray, "from_binary", nary_s_from_binary, -1);
+ rb_define_alias (rb_singleton_class(cNArray), "from_string", "from_binary");
+ rb_define_method(cNArray, "store_binary", nary_store_binary, -1);
+ rb_define_method(cNArray, "to_binary", nary_to_binary, 0);
+ rb_define_alias (cNArray, "to_string", "to_binary");
+ rb_define_method(cNArray, "marshal_dump", nary_marshal_dump, 0);
+ rb_define_method(cNArray, "marshal_load", nary_marshal_load, 1);
+
+ rb_define_method(cNArray, "byte_size", nary_byte_size, 0);
+
+ rb_define_method(cNArray, "cast_to", nary_cast_to, 1);
+
+ rb_define_method(cNArray, "coerce", nary_coerce, 1);
+
+ rb_define_method(cNArray, "column_major?", na_column_major_p, 0);
+ rb_define_method(cNArray, "row_major?", na_row_major_p, 0);
+ rb_define_method(cNArray, "byte_swapped?", na_byte_swapped_p, 0);
+ rb_define_method(cNArray, "host_order?", na_host_order_p, 0);
+
+ rb_define_method(cNArray, "inplace", na_inplace, 0);
+ rb_define_method(cNArray, "inplace?", na_inplace_p, 0);
+ rb_define_method(cNArray, "inplace!", na_inplace_bang, 0);
+ rb_define_method(cNArray, "out_of_place!", na_out_of_place_bang, 0);
+ rb_define_alias (cNArray, "not_inplace!", "out_of_place!");
+
+ rb_define_method(cNArray, "==", na_equal, 1);
+
+ id_allocate = rb_intern("allocate");
+ id_contiguous_stride = rb_intern(CONTIGUOUS_STRIDE);
+ //id_element_bit_size = rb_intern(ELEMENT_BIT_SIZE);
+ id_element_byte_size = rb_intern(ELEMENT_BYTE_SIZE);
+
+ id_fill = rb_intern("fill");
+ id_seq = rb_intern("seq");
+ id_logseq = rb_intern("logseq");
+ id_eye = rb_intern("eye");
+ id_UPCAST = rb_intern("UPCAST");
+ id_cast = rb_intern("cast");
+ id_dup = rb_intern("dup");
+ id_to_host = rb_intern("to_host");
+ id_bracket = rb_intern("[]");
+ id_shift_left = rb_intern("<<");
+ id_eq = rb_intern("eq");
+ id_count_false = rb_intern("count_false");
+ id_axis = rb_intern("axis");
+ id_nan = rb_intern("nan");
+ id_keepdims = rb_intern("keepdims");
+
+ sym_reduce = ID2SYM(rb_intern("reduce"));
+ sym_option = ID2SYM(rb_intern("option"));
+ sym_loop_opt = ID2SYM(rb_intern("loop_opt"));
+ sym_init = ID2SYM(rb_intern("init"));
+
+ Init_nary_step();
+ Init_nary_index();
+
+ Init_nary_data();
+ Init_nary_ndloop();
+
+ Init_numo_dcomplex();
+ Init_numo_dfloat();
+ Init_numo_scomplex();
+ Init_numo_sfloat();
+
+ Init_numo_int64();
+ Init_numo_uint64();
+ Init_numo_int32();
+ Init_numo_uint32();
+ Init_numo_int16();
+ Init_numo_uint16();
+ Init_numo_int8();
+ Init_numo_uint8();
+
+ Init_numo_bit();
+ Init_numo_robject();
+
+ Init_nary_math();
+
+ Init_nary_rand();
+ Init_nary_array();
+ Init_nary_struct();
+}
diff --git a/ext/numo/narray/ndloop.c b/ext/numo/narray/ndloop.c
new file mode 100644
index 0000000..e431a7f
--- /dev/null
+++ b/ext/numo/narray/ndloop.c
@@ -0,0 +1,1961 @@
+/*
+ ndloop.c
+ Numerical Array Extension for Ruby
+ (C) Copyright 1999-2017 by Masahiro TANAKA
+*/
+
+#include <ruby.h>
+#include "numo/narray.h"
+
+#if 0
+#define DBG(x) x
+#else
+#define DBG(x)
+#endif
+
+#ifdef HAVE_STDARG_PROTOTYPES
+#include <stdarg.h>
+#define va_init_list(a,b) va_start(a,b)
+#else
+#include <varargs.h>
+#define va_init_list(a,b) va_start(a)
+#endif
+
+typedef struct NA_BUFFER_COPY {
+ int ndim;
+ size_t elmsz;
+ size_t *n;
+ char *src_ptr;
+ char *buf_ptr;
+ na_loop_iter_t *src_iter;
+ na_loop_iter_t *buf_iter;
+} na_buffer_copy_t;
+
+typedef struct NA_LOOP_XARGS {
+ na_loop_iter_t *iter; // moved from na_loop_t
+ na_buffer_copy_t *bufcp; // copy data to buffer
+ int flag; // NDL_READ NDL_WRITE
+ bool free_user_iter; // alloc LARG(lp,j).iter=lp->xargs[j].iter
+} na_loop_xargs_t;
+
+typedef struct NA_MD_LOOP {
+ int narg;
+ int nin;
+ int ndim; // n of total dimention
+ unsigned int copy_flag; // set i-th bit if i-th arg is cast
+ size_t *n_ptr; // memory for n
+ na_loop_iter_t *iter_ptr; // memory for iter
+ size_t *n; // n of elements for each dim
+ na_loop_t user; // loop in user function
+ na_loop_xargs_t *xargs; // extra data for each arg
+ int writeback; // write back result to i-th arg
+ int init_aidx; // index of initializer argument
+ int reduce_dim;
+ int *trans_map;
+ VALUE vargs;
+ VALUE reduce;
+ VALUE loop_opt;
+ ndfunc_t *ndfunc;
+ void (*loop_func)();
+} na_md_loop_t;
+
+#define LARG(lp,iarg) ((lp)->user.args[iarg])
+#define LITER(lp,idim,iarg) ((lp)->xargs[iarg].iter[idim])
+#define LITER_SRC(lp,idim) ((lp)->src_iter[idim])
+#define LBUFCP(lp,j) ((lp)->xargs[j].bufcp)
+
+#define CASTABLE(t) (RTEST(t) && (t)!=OVERWRITE)
+
+#define NDL_READ 1
+#define NDL_WRITE 2
+#define NDL_READ_WRITE (NDL_READ|NDL_WRITE)
+
+static ID id_cast;
+static ID id_extract;
+
+static inline VALUE
+nary_type_s_cast(VALUE type, VALUE obj)
+{
+ return rb_funcall(type,id_cast,1,obj);
+}
+
+static void
+print_ndfunc(ndfunc_t *nf) {
+ volatile VALUE t;
+ int i, k;
+ printf("ndfunc_t = 0x%"SZF"x {\n",(size_t)nf);
+ printf(" func = 0x%"SZF"x\n", (size_t)nf->func);
+ printf(" flag = 0x%"SZF"x\n", (size_t)nf->flag);
+ printf(" nin = %d\n", nf->nin);
+ printf(" nout = %d\n", nf->nout);
+ printf(" ain = 0x%"SZF"x\n", (size_t)nf->ain);
+ for (i=0; i<nf->nin; i++) {
+ t = rb_inspect(nf->ain[i].type);
+ printf(" ain[%d].type = %s\n", i, StringValuePtr(t));
+ printf(" ain[%d].dim = %d\n", i, nf->ain[i].dim);
+ }
+ printf(" aout = 0x%"SZF"x\n", (size_t)nf->aout);
+ for (i=0; i<nf->nout; i++) {
+ t = rb_inspect(nf->aout[i].type);
+ printf(" aout[%d].type = %s\n", i, StringValuePtr(t));
+ printf(" aout[%d].dim = %d\n", i, nf->aout[i].dim);
+ for (k=0; k<nf->aout[i].dim; k++) {
+ printf(" aout[%d].shape[%d] = %"SZF"u\n", i, k, nf->aout[i].shape[k]);
+ }
+ }
+ printf("}\n");
+}
+
+
+static void
+print_ndloop(na_md_loop_t *lp) {
+ int i,j,nd;
+ printf("na_md_loop_t = 0x%"SZF"x {\n",(size_t)lp);
+ printf(" narg = %d\n", lp->narg);
+ printf(" nin = %d\n", lp->nin);
+ printf(" ndim = %d\n", lp->ndim);
+ printf(" copy_flag = %x\n", lp->copy_flag);
+ printf(" writeback = %d\n", lp->writeback);
+ printf(" init_aidx = %d\n", lp->init_aidx);
+ printf(" reduce_dim = %d\n", lp->reduce_dim);
+ printf(" trans_map = 0x%"SZF"x\n", (size_t)lp->trans_map);
+ nd = lp->ndim + lp->user.ndim;
+ for (i=0; i<nd; i++) {
+ printf(" trans_map[%d] = %d\n", i, lp->trans_map[i]);
+ }
+ printf(" n = 0x%"SZF"x\n", (size_t)lp->n);
+ nd = lp->ndim + lp->user.ndim;
+ for (i=0; i<=lp->ndim; i++) {
+ printf(" n[%d] = %"SZF"u\n", i, lp->n[i]);
+ }
+ printf(" user.n = 0x%"SZF"x\n", (size_t)lp->user.n);
+ if (lp->user.n) {
+ for (i=0; i<=lp->user.ndim; i++) {
+ printf(" user.n[%d] = %"SZF"u\n", i, lp->user.n[i]);
+ }
+ }
+ printf(" xargs = 0x%"SZF"x\n", (size_t)lp->xargs);
+ printf(" iter_ptr = 0x%"SZF"x\n", (size_t)lp->iter_ptr);
+ printf(" user.narg = %d\n", lp->user.narg);
+ printf(" user.ndim = %d\n", lp->user.ndim);
+ printf(" user.args = 0x%"SZF"x\n", (size_t)lp->user.args);
+ for (j=0; j<lp->narg; j++) {
+ }
+ printf(" user.opt_ptr = 0x%"SZF"x\n", (size_t)lp->user.opt_ptr);
+ if (lp->reduce==Qnil) {
+ printf(" reduce = nil\n");
+ } else {
+ printf(" reduce = 0x%x\n", NUM2INT(lp->reduce));
+ }
+ for (j=0; j<lp->narg; j++) {
+ printf("--user.args[%d]--\n", j);
+ printf(" user.args[%d].ptr = 0x%"SZF"x\n", j, (size_t)LARG(lp,j).ptr);
+ printf(" user.args[%d].elmsz = %"SZF"d\n", j, LARG(lp,j).elmsz);
+ printf(" user.args[%d].value = 0x%"PRI_VALUE_PREFIX"x\n", j, LARG(lp,j).value);
+ printf(" user.args[%d].ndim = %d\n", j, LARG(lp,j).ndim);
+ printf(" user.args[%d].shape = 0x%"SZF"x\n", j, (size_t)LARG(lp,j).shape);
+ if (LARG(lp,j).shape) {
+ for (i=0; i<LARG(lp,j).ndim; i++) {
+ printf(" user.args[%d].shape[%d] = %"SZF"d\n", j, i, LARG(lp,j).shape[i]);
+ }
+ }
+ printf(" user.args[%d].iter = 0x%"SZF"x\n", j,(size_t)lp->user.args[j].iter);
+ if (lp->user.args[j].iter) {
+ for (i=0; i<lp->user.ndim; i++) {
+ printf(" &user.args[%d].iter[%d] = 0x%"SZF"x\n", j,i, (size_t)&lp->user.args[j].iter[i]);
+ printf(" user.args[%d].iter[%d].pos = %"SZF"u\n", j,i, lp->user.args[j].iter[i].pos);
+ printf(" user.args[%d].iter[%d].step = %"SZF"u\n", j,i, lp->user.args[j].iter[i].step);
+ printf(" user.args[%d].iter[%d].idx = 0x%"SZF"x\n", j,i, (size_t)lp->user.args[j].iter[i].idx);
+ }
+ }
+ //
+ printf(" xargs[%d].flag = %d\n", j, lp->xargs[j].flag);
+ printf(" xargs[%d].free_user_iter = %d\n", j, lp->xargs[j].free_user_iter);
+ for (i=0; i<=nd; i++) {
+ printf(" &xargs[%d].iter[%d] = 0x%"SZF"x\n", j,i, (size_t)&LITER(lp,i,j));
+ printf(" xargs[%d].iter[%d].pos = %"SZF"u\n", j,i, LITER(lp,i,j).pos);
+ printf(" xargs[%d].iter[%d].step = %"SZF"u\n", j,i, LITER(lp,i,j).step);
+ printf(" xargs[%d].iter[%d].idx = 0x%"SZF"x\n", j,i, (size_t)LITER(lp,i,j).idx);
+ }
+ printf(" xargs[%d].bufcp = 0x%"SZF"x\n", j, (size_t)lp->xargs[j].bufcp);
+ if (lp->xargs[j].bufcp) {
+ printf(" xargs[%d].bufcp->ndim = %d\n", j, lp->xargs[j].bufcp->ndim);
+ printf(" xargs[%d].bufcp->elmsz = %"SZF"d\n", j, lp->xargs[j].bufcp->elmsz);
+ printf(" xargs[%d].bufcp->n = 0x%"SZF"x\n", j, (size_t)lp->xargs[j].bufcp->n);
+ printf(" xargs[%d].bufcp->src_ptr = 0x%"SZF"x\n", j, (size_t)lp->xargs[j].bufcp->src_ptr);
+ printf(" xargs[%d].bufcp->buf_ptr = 0x%"SZF"x\n", j, (size_t)lp->xargs[j].bufcp->buf_ptr);
+ printf(" xargs[%d].bufcp->src_iter = 0x%"SZF"x\n", j, (size_t)lp->xargs[j].bufcp->src_iter);
+ printf(" xargs[%d].bufcp->buf_iter = 0x%"SZF"x\n", j, (size_t)lp->xargs[j].bufcp->buf_iter);
+ }
+ }
+ printf("}\n");
+}
+
+
+static unsigned int
+ndloop_func_loop_spec(ndfunc_t *nf, int user_ndim)
+{
+ unsigned int f=0;
+ // If user function supports LOOP
+ if (user_ndim > 0 || NDF_TEST(nf,NDF_HAS_LOOP)) {
+ if (!NDF_TEST(nf,NDF_STRIDE_LOOP)) {
+ f |= 1;
+ }
+ if (!NDF_TEST(nf,NDF_INDEX_LOOP)) {
+ f |= 2;
+ }
+ }
+ return f;
+}
+
+
+
+
+static int
+ndloop_cast_required(VALUE type, VALUE value)
+{
+ return CASTABLE(type) && type != CLASS_OF(value);
+}
+
+static int
+ndloop_castable_type(VALUE type)
+{
+ return rb_obj_is_kind_of(type, rb_cClass) && RTEST(rb_class_inherited_p(type, cNArray));
+}
+
+static void
+ndloop_cast_error(VALUE type, VALUE value)
+{
+ VALUE x = rb_inspect(type);
+ char* s = StringValueCStr(x);
+ rb_bug("fail cast from %s to %s", rb_obj_classname(value),s);
+ rb_raise(rb_eTypeError,"fail cast from %s to %s",
+ rb_obj_classname(value), s);
+}
+
+// convert input argeuments given by RARRAY_PTR(args)[j]
+// to type specified by nf->args[j].type
+// returns copy_flag where nth-bit is set if nth argument is converted.
+static unsigned int
+ndloop_cast_args(ndfunc_t *nf, VALUE args)
+{
+ int j;
+ unsigned int copy_flag=0;
+ VALUE type, value;
+
+ for (j=0; j<nf->nin; j++) {
+
+ type = nf->ain[j].type;
+ if (TYPE(type)==T_SYMBOL)
+ continue;
+ value = RARRAY_AREF(args,j);
+ if (!ndloop_cast_required(type, value))
+ continue;
+
+ if (ndloop_castable_type(type)) {
+ RARRAY_ASET(args,j,nary_type_s_cast(type, value));
+ copy_flag |= 1<<j;
+ } else {
+ ndloop_cast_error(type, value);
+ }
+ }
+
+ RB_GC_GUARD(type); RB_GC_GUARD(value);
+ return copy_flag;
+}
+
+
+static void
+ndloop_handle_symbol_in_ain(VALUE type, VALUE value, int at, na_md_loop_t *lp)
+{
+ if (type==sym_reduce) {
+ lp->reduce = value;
+ }
+ else if (type==sym_option) {
+ lp->user.option = value;
+ }
+ else if (type==sym_loop_opt) {
+ lp->loop_opt = value;
+ }
+ else if (type==sym_init) {
+ lp->init_aidx = at;
+ }
+ else {
+ rb_bug("ndloop parse_options: unknown type");
+ }
+}
+
+static inline int
+max2(int x, int y)
+{
+ return x > y ? x : y;
+}
+
+static void
+ndloop_find_max_dimension(na_md_loop_t *lp, ndfunc_t *nf, VALUE args)
+{
+ int j;
+ int nin=0; // number of input objects (except for symbols)
+ int user_nd=0; // max dimension of user function
+ int loop_nd=0; // max dimension of md-loop
+
+ for (j=0; j<RARRAY_LEN(args); j++) {
+ VALUE t = nf->ain[j].type;
+ VALUE v = RARRAY_AREF(args,j);
+ if (TYPE(t)==T_SYMBOL) {
+ ndloop_handle_symbol_in_ain(t, v, j, lp);
+ } else {
+ nin++;
+ user_nd = max2(user_nd, nf->ain[j].dim);
+ if (IsNArray(v))
+ loop_nd = max2(loop_nd, RNARRAY_NDIM(v) - nf->ain[j].dim);
+ }
+ }
+
+ lp->narg = lp->user.narg = nin + nf->nout;
+ lp->nin = nin;
+ lp->ndim = loop_nd;
+ lp->user.ndim = user_nd;
+}
+
+/*
+ user-dimension:
+ user_nd = MAX( nf->args[j].dim )
+
+ user-support dimension:
+
+ loop dimension:
+ loop_nd
+*/
+
+static void
+ndloop_alloc(na_md_loop_t *lp, ndfunc_t *nf, VALUE args,
+ void *opt_ptr, unsigned int copy_flag,
+ void (*loop_func)(ndfunc_t*, na_md_loop_t*))
+{
+ int i,j;
+ int narg;
+ int max_nd;
+
+ long args_len;
+
+ na_loop_iter_t *iter;
+
+ int trans_dim;
+ unsigned int f;
+
+ args_len = RARRAY_LEN(args);
+
+ if (args_len != nf->nin) {
+ rb_bug("wrong number of arguments for ndfunc (%lu for %d)",
+ args_len, nf->nin);
+ }
+
+ lp->vargs = args;
+ lp->ndfunc = nf;
+ lp->loop_func = loop_func;
+ lp->copy_flag = copy_flag;
+
+ lp->reduce = Qnil;
+ lp->user.option = Qnil;
+ lp->user.opt_ptr = opt_ptr;
+ lp->user.err_type = Qfalse;
+ lp->loop_opt = Qnil;
+ lp->writeback = -1;
+ lp->init_aidx = -1;
+
+ lp->n = NULL;
+ lp->n_ptr = NULL;
+ lp->xargs = NULL;
+ lp->user.args = NULL;
+ lp->user.n = NULL;
+ lp->iter_ptr = NULL;
+ lp->trans_map = NULL;
+
+ ndloop_find_max_dimension(lp, nf, args);
+ narg = lp->nin + nf->nout;
+ max_nd = lp->ndim + lp->user.ndim;
+
+ lp->n = lp->n_ptr = ALLOC_N(size_t, max_nd+1);
+ lp->xargs = ALLOC_N(na_loop_xargs_t, narg);
+ lp->user.args = ALLOC_N(na_loop_args_t, narg);
+ iter = ALLOC_N(na_loop_iter_t, narg*(max_nd+1));
+ lp->iter_ptr = iter;
+
+ for (j=0; j<narg; j++) {
+ LARG(lp,j).value = Qnil;
+ LARG(lp,j).iter = NULL;
+ LARG(lp,j).shape = NULL;
+ LARG(lp,j).ndim = 0;
+ lp->xargs[j].iter = &(iter[(max_nd+1)*j]);
+ lp->xargs[j].bufcp = NULL;
+ lp->xargs[j].flag = (j<nf->nin) ? NDL_READ : NDL_WRITE;
+ lp->xargs[j].free_user_iter = 0;
+ }
+
+ for (i=0; i<=max_nd; i++) {
+ lp->n[i] = 1;
+ for (j=0; j<narg; j++) {
+ LITER(lp,i,j).pos = 0;
+ LITER(lp,i,j).step = 0;
+ LITER(lp,i,j).idx = NULL;
+ }
+ }
+
+ // transpose reduce-dimensions to last dimensions
+ // array loop
+ // [*,+,*,+,*] => [*,*,*,+,+]
+ // trans_map=[0,3,1,4,2] <= [0,1,2,3,4]
+ lp->trans_map = ALLOC_N(int, max_nd+1);
+ if (NDF_TEST(nf,NDF_FLAT_REDUCE) && RTEST(lp->reduce)) {
+ trans_dim = 0;
+ for (i=0; i<max_nd; i++) {
+ if (na_test_reduce(lp->reduce, i)) {
+ lp->trans_map[i] = -1;
+ } else {
+ lp->trans_map[i] = trans_dim++;
+ }
+ }
+ j = trans_dim;
+ for (i=0; i<max_nd; i++) {
+ if (lp->trans_map[i] == -1) {
+ lp->trans_map[i] = j++;
+ }
+ }
+ lp->reduce_dim = max_nd - trans_dim;
+ f = 0;
+ for (i=trans_dim; i<max_nd; i++) {
+ f |= 1<<i;
+ }
+ lp->reduce = INT2FIX(f);
+ } else {
+ for (i=0; i<max_nd; i++) {
+ lp->trans_map[i] = i;
+ }
+ lp->reduce_dim = 0;
+ }
+}
+
+
+static VALUE
+ndloop_release(VALUE vlp)
+{
+ int j;
+ VALUE v;
+ na_md_loop_t *lp = (na_md_loop_t*)(vlp);
+
+ for (j=0; j < lp->narg; j++) {
+ v = LARG(lp,j).value;
+ if (IsNArray(v)) {
+ na_release_lock(v);
+ }
+ }
+ //xfree(lp);
+ for (j=0; j<lp->narg; j++) {
+ //printf("lp->xargs[%d].bufcp=%lx\n",j,(size_t)(lp->xargs[j].bufcp));
+ if (lp->xargs[j].bufcp) {
+ xfree(lp->xargs[j].bufcp->buf_iter);
+ xfree(lp->xargs[j].bufcp->buf_ptr);
+ xfree(lp->xargs[j].bufcp->n);
+ xfree(lp->xargs[j].bufcp);
+ if (lp->xargs[j].free_user_iter) {
+ xfree(LARG(lp,j).iter);
+ }
+ }
+ }
+ if (lp->trans_map) xfree(lp->trans_map);
+ xfree(lp->xargs);
+ xfree(lp->iter_ptr);
+ xfree(lp->user.args);
+ xfree(lp->n_ptr);
+ //rb_gc_force_recycle(vlp);
+ return Qnil;
+}
+
+
+/*
+ set lp->n[i] (shape of n-d iteration) here
+*/
+static void
+ndloop_check_shape(na_md_loop_t *lp, int nf_dim, narray_t *na)
+{
+ int i, k;
+ size_t n;
+ int dim_beg;
+
+ dim_beg = lp->ndim + nf_dim - na->ndim;
+
+ for (k = na->ndim - nf_dim - 1; k>=0; k--) {
+ i = lp->trans_map[k + dim_beg];
+ n = na->shape[k];
+ // if n==1 then repeat this dimension
+ if (n != 1) {
+ if (lp->n[i] == 1) {
+ lp->n[i] = n;
+ } else if (lp->n[i] != n) {
+ // inconsistent array shape
+ rb_raise(nary_eShapeError,"shape1[%d](=%"SZF"u) != shape2[%d](=%"SZF"u)",
+ i, lp->n[i], k, n);
+ }
+ }
+ }
+}
+
+
+/*
+na->shape[i] == lp->n[ dim_map[i] ]
+ */
+static void
+ndloop_set_stepidx(na_md_loop_t *lp, int j, VALUE vna, int *dim_map, int rwflag)
+{
+ size_t n, s;
+ int i, k;
+ stridx_t sdx;
+ narray_t *na;
+
+ LARG(lp,j).value = vna;
+ LARG(lp,j).elmsz = nary_element_stride(vna);
+ if (rwflag == NDL_READ) {
+ LARG(lp,j).ptr = na_get_pointer_for_read(vna);
+ } else
+ if (rwflag == NDL_WRITE) {
+ LARG(lp,j).ptr = na_get_pointer_for_write(vna);
+ } else
+ if (rwflag == NDL_READ_WRITE) {
+ LARG(lp,j).ptr = na_get_pointer_for_read_write(vna);
+ } else {
+ rb_bug("invalid value for read-write flag");
+ }
+ GetNArray(vna,na);
+
+ switch(NA_TYPE(na)) {
+ case NARRAY_DATA_T:
+ if (NA_DATA_PTR(na)==NULL && NA_SIZE(na)>0) {
+ rb_bug("cannot read no-data NArray");
+ rb_raise(rb_eRuntimeError,"cannot read no-data NArray");
+ }
+ // through
+ case NARRAY_FILEMAP_T:
+ s = LARG(lp,j).elmsz;
+ for (k=na->ndim; k--;) {
+ n = na->shape[k];
+ if (n > 1) {
+ i = dim_map[k];
+ //printf("n=%d k=%d i=%d\n",n,k,i);
+ LITER(lp,i,j).step = s;
+ LITER(lp,i,j).idx = NULL;
+ }
+ s *= n;
+ }
+ LITER(lp,0,j).pos = 0;
+ break;
+ case NARRAY_VIEW_T:
+ LITER(lp,0,j).pos = NA_VIEW_OFFSET(na);
+ for (k=0; k<na->ndim; k++) {
+ n = na->shape[k];
+ sdx = NA_VIEW_STRIDX(na)[k];
+ if (n > 1) {
+ i = dim_map[k];
+ if (SDX_IS_INDEX(sdx)) {
+ LITER(lp,i,j).step = 0;
+ LITER(lp,i,j).idx = SDX_GET_INDEX(sdx);
+ } else {
+ LITER(lp,i,j).step = SDX_GET_STRIDE(sdx);
+ LITER(lp,i,j).idx = NULL;
+ }
+ } else if (n==1) {
+ if (SDX_IS_INDEX(sdx)) {
+ LITER(lp,0,j).pos += SDX_GET_INDEX(sdx)[0];
+ }
+ }
+ }
+ break;
+ default:
+ rb_bug("invalid narray internal type");
+ }
+}
+
+
+
+static void
+ndloop_init_args(ndfunc_t *nf, na_md_loop_t *lp, VALUE args)
+{
+ int i, j;
+ VALUE v;
+ narray_t *na;
+ int nf_dim;
+ int dim_beg;
+ int *dim_map;
+ int max_nd = lp->ndim + lp->user.ndim;
+ int flag;
+ size_t s;
+
+/*
+na->shape[i] == lp->n[ dim_map[i] ]
+ */
+ dim_map = ALLOCA_N(int, max_nd);
+
+ // input arguments
+ for (j=0; j<nf->nin; j++) {
+ if (TYPE(nf->ain[j].type)==T_SYMBOL) {
+ continue;
+ }
+ v = RARRAY_AREF(args,j);
+ if (IsNArray(v)) {
+ // set LARG(lp,j) with v
+ GetNArray(v,na);
+ nf_dim = nf->ain[j].dim;
+ if (nf_dim > na->ndim) {
+ rb_raise(nary_eDimensionError,"requires >= %d-dimensioal array "
+ "while %d-dimensional array is given",nf_dim,na->ndim);
+ }
+ ndloop_check_shape(lp, nf_dim, na);
+ dim_beg = lp->ndim + nf->ain[j].dim - na->ndim;
+ for (i=0; i<na->ndim; i++) {
+ dim_map[i] = lp->trans_map[i+dim_beg];
+ //printf("dim_map[%d]=%d na->shape[%d]=%d\n",i,dim_map[i],i,na->shape[i]);
+ }
+ if (nf->ain[j].type==OVERWRITE) {
+ lp->xargs[j].flag = flag = NDL_WRITE;
+ } else {
+ lp->xargs[j].flag = flag = NDL_READ;
+ }
+ ndloop_set_stepidx(lp, j, v, dim_map, flag);
+ LARG(lp,j).ndim = nf_dim;
+ if (nf_dim > 0) {
+ LARG(lp,j).shape = na->shape + (na->ndim - nf_dim);
+ }
+ } else if (TYPE(v)==T_ARRAY) {
+ LARG(lp,j).value = v;
+ LARG(lp,j).elmsz = sizeof(VALUE);
+ LARG(lp,j).ptr = NULL;
+ for (i=0; i<=max_nd; i++) {
+ LITER(lp,i,j).step = 1;
+ }
+ }
+ }
+ // check whether # of element is zero
+ for (s=1,i=0; i<=max_nd; i++) {
+ s *= lp->n[i];
+ }
+ if (s==0) {
+ for (i=0; i<=max_nd; i++) {
+ lp->n[i] = 0;
+ }
+ }
+}
+
+
+static int
+ndloop_check_inplace(VALUE type, int na_ndim, size_t *na_shape, VALUE v)
+{
+ int i;
+ narray_t *na;
+
+ // type check
+ if (type != CLASS_OF(v)) {
+ return 0;
+ }
+ GetNArray(v,na);
+ // shape check
+ if (na->ndim != na_ndim) {
+ return 0;
+ }
+ for (i=0; i<na_ndim; i++) {
+ if (na_shape[i] != na->shape[i]) {
+ return 0;
+ }
+ }
+ // v is selected as output
+ return 1;
+}
+
+static VALUE
+ndloop_find_inplace(ndfunc_t *nf, na_md_loop_t *lp, VALUE type,
+ int na_ndim, size_t *na_shape, VALUE args)
+{
+ int j;
+ VALUE v;
+
+ // find inplace
+ for (j=0; j<nf->nin; j++) {
+ v = RARRAY_AREF(args,j);
+ if (IsNArray(v)) {
+ if (TEST_INPLACE(v)) {
+ if (ndloop_check_inplace(type,na_ndim,na_shape,v)) {
+ // if already copied, create outary and write-back
+ if (lp->copy_flag & (1<<j)) {
+ lp->writeback = j;
+ }
+ return v;
+ }
+ }
+ }
+ }
+ // find casted or copied input array
+ for (j=0; j<nf->nin; j++) {
+ if (lp->copy_flag & (1<<j)) {
+ v = RARRAY_AREF(args,j);
+ if (ndloop_check_inplace(type,na_ndim,na_shape,v)) {
+ return v;
+ }
+ }
+ }
+ return Qnil;
+}
+
+
+
+static VALUE
+ndloop_get_arg_type(ndfunc_t *nf, VALUE args, VALUE t)
+{
+ int i;
+
+ // if type is FIXNUM, get the type of i-th argument
+ if (FIXNUM_P(t)) {
+ i = FIX2INT(t);
+ if (i<0 || i>=nf->nin) {
+ rb_bug("invalid type: index (%d) out of # of args",i);
+ }
+ t = nf->ain[i].type;
+ // if i-th type is Qnil, get the type of i-th input value
+ if (!CASTABLE(t)) {
+ t = CLASS_OF(RARRAY_AREF(args,i));
+ }
+ }
+ return t;
+}
+
+
+static VALUE
+ndloop_set_output_narray(ndfunc_t *nf, na_md_loop_t *lp, int k,
+ VALUE type, VALUE args)
+{
+ int i, j;
+ int na_ndim;
+ int lp_dim;
+ volatile VALUE v=Qnil;
+ size_t *na_shape;
+ int *dim_map;
+ int flag = NDL_READ_WRITE;
+ int nd;
+ int max_nd = lp->ndim + nf->aout[k].dim;
+
+ na_shape = ALLOCA_N(size_t, max_nd);
+ dim_map = ALLOCA_N(int, max_nd);
+
+ //printf("max_nd=%d lp->ndim=%d\n",max_nd,lp->ndim);
+
+ // md-loop shape
+ na_ndim = 0;
+ for (i=0; i<lp->ndim; i++) {
+ // na_shape[i] == lp->n[lp->trans_map[i]]
+ lp_dim = lp->trans_map[i];
+ //printf("i=%d lp_dim=%d\n",i,lp_dim);
+ if (NDF_TEST(nf,NDF_CUM)) { // cumulate with shape kept
+ na_shape[na_ndim] = lp->n[lp_dim];
+ } else
+ if (na_test_reduce(lp->reduce,lp_dim)) { // accumulate dimension
+ if (NDF_TEST(nf,NDF_KEEP_DIM)) {
+ na_shape[na_ndim] = 1; // leave it
+ } else {
+ continue; // delete dimension
+ }
+ } else {
+ na_shape[na_ndim] = lp->n[lp_dim];
+ }
+ //printf("i=%d lp_dim=%d na_shape[%d]=%ld\n",i,lp_dim,i,na_shape[i]);
+ dim_map[na_ndim++] = lp_dim;
+ //dim_map[lp_dim] = na_ndim++;
+ }
+
+ // user-specified shape
+ for (i=0; i<nf->aout[k].dim; i++) {
+ na_shape[na_ndim] = nf->aout[k].shape[i];
+ dim_map[na_ndim++] = i + lp->ndim;
+ }
+
+ // find inplace from input arrays
+ if (k==0 && NDF_TEST(nf,NDF_INPLACE)) {
+ v = ndloop_find_inplace(nf,lp,type,na_ndim,na_shape,args);
+ }
+ if (!RTEST(v)) {
+ // new object
+ v = nary_new(type, na_ndim, na_shape);
+ flag = NDL_WRITE;
+ }
+
+ j = lp->nin + k;
+ ndloop_set_stepidx(lp, j, v, dim_map, flag);
+ LARG(lp,j).ndim = nd = nf->aout[k].dim;
+ if (nd > 0) {
+ LARG(lp,j).shape = nf->aout[k].shape;
+ }
+
+ return v;
+}
+
+static VALUE
+ndloop_set_output(ndfunc_t *nf, na_md_loop_t *lp, VALUE args)
+{
+ int i, j, k, idx;
+ volatile VALUE v, t, results;
+ VALUE init;
+
+ int max_nd = lp->ndim + lp->user.ndim;
+
+ // output results
+ results = rb_ary_new2(nf->nout);
+
+ for (k=0; k<nf->nout; k++) {
+ t = nf->aout[k].type;
+ t = ndloop_get_arg_type(nf,args,t);
+
+ if (rb_obj_is_kind_of(t, rb_cClass)) {
+ if (RTEST(rb_class_inherited_p(t, cNArray))) {
+ // NArray
+ v = ndloop_set_output_narray(nf,lp,k,t,args);
+ rb_ary_push(results, v);
+ }
+ else if (RTEST(rb_class_inherited_p(t, rb_cArray))) {
+ // Ruby Array
+ j = lp->nin + k;
+ for (i=0; i<=max_nd; i++) {
+ LITER(lp,i,j).step = sizeof(VALUE);
+ }
+ LARG(lp,j).value = t;
+ LARG(lp,j).elmsz = sizeof(VALUE);
+ } else {
+ rb_raise(rb_eRuntimeError,"ndloop_set_output: invalid for type");
+ }
+ }
+ }
+
+ // initialilzer
+ k = lp->init_aidx;
+ if (k > -1) {
+ idx = nf->ain[k].dim;
+ v = RARRAY_AREF(results,idx);
+ init = RARRAY_AREF(args,k);
+ na_store(v,init);
+ }
+
+ return results;
+}
+
+
+static void
+ndfunc_contract_loop(na_md_loop_t *lp)
+{
+ int i,j,k,success,cnt=0;
+ int red0, redi;
+
+ redi = na_test_reduce(lp->reduce,0);
+
+ //for (i=0; i<lp->ndim; i++) {
+ // printf("lp->n[%d]=%lu\n",i,lp->n[i]);
+ //}
+
+ for (i=1; i<lp->ndim; i++) {
+ red0 = redi;
+ redi = na_test_reduce(lp->reduce,i);
+ //printf("contract i=%d reduce_cond=%d %d\n",i,red0,redi);
+ if (red0 != redi) {
+ continue;
+ }
+ success = 1;
+ for (j=0; j<lp->narg; j++) {
+ if (!(LITER(lp,i,j).idx == NULL &&
+ LITER(lp,i-1,j).idx == NULL &&
+ LITER(lp,i-1,j).step == LITER(lp,i,j).step*(ssize_t)(lp->n[i]))) {
+ success = 0;
+ break;
+ }
+ }
+ if (success) {
+ //printf("contract i=%d-th and %d-th, lp->n[%d]=%"SZF"d, lp->n[%d]=%"SZF"d\n",
+ // i-1,i, i,lp->n[i], i-1,lp->n[i-1]);
+ // contract (i-1)-th and i-th dimension
+ lp->n[i] *= lp->n[i-1];
+ // shift dimensions
+ for (k=i-1; k>cnt; k--) {
+ lp->n[k] = lp->n[k-1];
+ }
+ //printf("k=%d\n",k);
+ for (; k>=0; k--) {
+ lp->n[k] = 1;
+ }
+ for (j=0; j<lp->narg; j++) {
+ for (k=i-1; k>cnt; k--) {
+ LITER(lp,k,j) = LITER(lp,k-1,j);
+ }
+ }
+ if (redi) {
+ lp->reduce_dim--;
+ }
+ cnt++;
+ }
+ }
+ //printf("contract cnt=%d\n",cnt);
+ if (cnt>0) {
+ for (j=0; j<lp->narg; j++) {
+ LITER(lp,cnt,j).pos = LITER(lp,0,j).pos;
+ lp->xargs[j].iter = &LITER(lp,cnt,j);
+ }
+ lp->n = &(lp->n[cnt]);
+ lp->ndim -= cnt;
+ //for (i=0; i<lp->ndim; i++) {printf("lp->n[%d]=%lu\n",i,lp->n[i]);}
+ }
+}
+
+
+static void
+ndfunc_set_user_loop(ndfunc_t *nf, na_md_loop_t *lp)
+{
+ int j, ud=0;
+
+ if (lp->reduce_dim > 0) {
+ ud = lp->reduce_dim;
+ }
+ else if (lp->ndim > 0 && NDF_TEST(nf,NDF_HAS_LOOP)) {
+ ud = 1;
+ }
+ else {
+ goto skip_ud;
+ }
+ if (ud > lp->ndim) {
+ rb_bug("Reduce-dimension is larger than loop-dimension");
+ }
+ // increase user dimension
+ lp->user.ndim += ud;
+ lp->ndim -= ud;
+ for (j=0; j<lp->narg; j++) {
+ if (LARG(lp,j).shape) {
+ rb_bug("HAS_LOOP or reduce-dimension=%d conflicts with user-dimension",lp->reduce_dim);
+ }
+ LARG(lp,j).ndim += ud;
+ LARG(lp,j).shape = &(lp->n[lp->ndim]);
+ //printf("LARG(lp,j).ndim=%d,LARG(lp,j).shape=%lx\n",LARG(lp,j).ndim,(size_t)LARG(lp,j).shape);
+ }
+ //printf("lp->reduce_dim=%d lp->user.ndim=%d lp->ndim=%d\n",lp->reduce_dim,lp->user.ndim,lp->ndim);
+
+ skip_ud:
+ lp->user.n = &(lp->n[lp->ndim]);
+ for (j=0; j<lp->narg; j++) {
+ LARG(lp,j).iter = &LITER(lp,lp->ndim,j);
+ //printf("in ndfunc_set_user_loop: lp->user.args[%d].iter=%lx\n",j,(size_t)(LARG(lp,j).iter));
+ }
+}
+
+
+static void
+ndfunc_set_bufcp(na_md_loop_t *lp, unsigned int loop_spec)
+{
+ unsigned int f;
+ int i, j;
+ int nd, ndim;
+ bool zero_step;
+ ssize_t n, sz, elmsz, stride, n_total; //, last_step;
+ size_t *buf_shape;
+ na_loop_iter_t *buf_iter=NULL, *src_iter;
+
+ //if (loop_spec==0) return;
+
+ n_total = lp->user.n[0];
+ for (i=1; i<lp->user.ndim; i++) {
+ n_total *= lp->user.n[i];
+ }
+
+ //for (j=0; j<lp->nin; j++) {
+ for (j=0; j<lp->narg; j++) {
+ //ndim = nd = lp->user.ndim;
+ ndim = nd = LARG(lp,j).ndim;
+ sz = elmsz = LARG(lp,j).elmsz;
+ src_iter = LARG(lp,j).iter;
+ //last_step = src_iter[ndim-1].step;
+ f = 0;
+ zero_step = 1;
+ for (i=ndim; i>0; ) {
+ i--;
+ if (LARG(lp,j).shape) {
+ n = LARG(lp,j).shape[i];
+ } else {
+ printf("shape is NULL\n");
+ n = lp->user.n[i];
+ }
+ stride = sz * n;
+ //printf("{j=%d,i=%d,ndim=%d,nd=%d,idx=%lx,step=%ld,n=%ld,sz=%ld,stride=%ld}\n",j,i,ndim,nd,(size_t)src_iter[i].idx,src_iter[i].step,n,sz,stride);
+ if (src_iter[i].idx) {
+ f |= 2; // INDEX LOOP
+ zero_step = 0;
+ } else {
+ if (src_iter[i].step != sz) {
+ f |= 1; // NON_CONTIGUOUS LOOP
+ } else {
+ // CONTIGUOUS LOOP
+ if (i==ndim-1) { // contract if last dimension
+ ndim = i;
+ elmsz = stride;
+ }
+ }
+ if (src_iter[i].step != 0) {
+ zero_step = 0;
+ }
+ }
+ sz = stride;
+ }
+ //printf("[j=%d f=%d loop_spec=%d zero_step=%d]\n",j,f,loop_spec,zero_step);
+
+ if (zero_step) {
+ // no buffer needed
+ continue;
+ }
+
+ // should check flatten-able loop to avoid buffering
+
+
+ // over loop_spec or reduce_loop is not contiguous
+ if (f & loop_spec || (lp->reduce_dim > 1 && ndim > 0)) {
+ //printf("(buf,nd=%d)",nd);
+ buf_iter = ALLOC_N(na_loop_iter_t,nd+3);
+ buf_shape = ALLOC_N(size_t,nd);
+ buf_iter[nd].pos = 0;
+ buf_iter[nd].step = 0;
+ buf_iter[nd].idx = NULL;
+ sz = LARG(lp,j).elmsz;
+ //last_step = sz;
+ for (i=nd; i>0; ) {
+ i--;
+ buf_iter[i].pos = 0;
+ buf_iter[i].step = sz;
+ buf_iter[i].idx = NULL;
+ //n = lp->user.n[i];
+ n = LARG(lp,j).shape[i];
+ buf_shape[i] = n;
+ sz *= n;
+ }
+ LBUFCP(lp,j) = ALLOC(na_buffer_copy_t);
+ LBUFCP(lp,j)->ndim = ndim;
+ LBUFCP(lp,j)->elmsz = elmsz;
+ LBUFCP(lp,j)->n = buf_shape;
+ LBUFCP(lp,j)->src_iter = src_iter;
+ LBUFCP(lp,j)->buf_iter = buf_iter;
+ LARG(lp,j).iter = buf_iter;
+ //printf("in ndfunc_set_bufcp(1): lp->user.args[%d].iter=%lx\n",j,(size_t)(LARG(lp,j).iter));
+ LBUFCP(lp,j)->src_ptr = LARG(lp,j).ptr;
+ LARG(lp,j).ptr = LBUFCP(lp,j)->buf_ptr = xmalloc(sz);
+ //printf("(LBUFCP(lp,%d)->buf_ptr=%lx)\n",j,(size_t)(LBUFCP(lp,j)->buf_ptr));
+ }
+ }
+
+#if 0
+ for (j=0; j<lp->narg; j++) {
+ ndim = lp->user.ndim;
+ src_iter = LARG(lp,j).iter;
+ last_step = src_iter[ndim-1].step;
+ if (lp->reduce_dim>1) {
+ //printf("(reduce_dim=%d,ndim=%d,nd=%d,n=%ld,lst=%ld)\n",lp->reduce_dim,ndim,nd,n_total,last_step);
+ buf_iter = ALLOC_N(na_loop_iter_t,2);
+ buf_iter[0].pos = LARG(lp,j).iter[0].pos;
+ buf_iter[0].step = last_step;
+ buf_iter[0].idx = NULL;
+ buf_iter[1].pos = 0;
+ buf_iter[1].step = 0;
+ buf_iter[1].idx = NULL;
+ LARG(lp,j).iter = buf_iter;
+ //printf("in ndfunc_set_bufcp(2): lp->user.args[%d].iter=%lx\n",j,(size_t)(LARG(lp,j).iter));
+ lp->xargs[j].free_user_iter = 1;
+ }
+ }
+#endif
+
+ // flatten reduce dimensions
+ if (lp->reduce_dim > 1) {
+#if 1
+ for (j=0; j<lp->narg; j++) {
+ ndim = lp->user.ndim;
+ LARG(lp,j).iter[0].step = LARG(lp,j).iter[ndim-1].step;
+ LARG(lp,j).iter[0].idx = NULL;
+ }
+#endif
+ lp->user.n[0] = n_total;
+ lp->user.ndim = 1;
+ }
+}
+
+
+static void
+ndloop_copy_to_buffer(na_buffer_copy_t *lp)
+{
+ size_t *c;
+ char *src, *buf;
+ int i;
+ int nd = lp->ndim;
+ size_t elmsz = lp->elmsz;
+ size_t buf_pos = 0;
+ DBG(size_t j);
+
+ //printf("\nto_buf nd=%d elmsz=%ld\n",nd,elmsz);
+ DBG(printf("<to buf> ["));
+ // zero-dimension
+ if (nd==0) {
+ src = lp->src_ptr + LITER_SRC(lp,0).pos;
+ buf = lp->buf_ptr;
+ memcpy(buf,src,elmsz);
+ DBG(for (j=0; j<elmsz/8; j++) {printf("%g,",((double*)(buf))[j]);});
+ goto loop_end;
+ }
+ // initialize loop counter
+ c = ALLOCA_N(size_t, nd+1);
+ for (i=0; i<=nd; i++) c[i]=0;
+ // loop body
+ for (i=0;;) {
+ // i-th dimension
+ for (; i<nd; i++) {
+ if (LITER_SRC(lp,i).idx) {
+ LITER_SRC(lp,i+1).pos = LITER_SRC(lp,i).pos + LITER_SRC(lp,i).idx[c[i]];
+ } else {
+ LITER_SRC(lp,i+1).pos = LITER_SRC(lp,i).pos + LITER_SRC(lp,i).step*c[i];
+ }
+ }
+ src = lp->src_ptr + LITER_SRC(lp,nd).pos;
+ buf = lp->buf_ptr + buf_pos;
+ memcpy(buf,src,elmsz);
+ DBG(for (j=0; j<elmsz/8; j++) {printf("%g,",((double*)(buf))[j]);});
+ buf_pos += elmsz;
+ // count up
+ for (;;) {
+ if (i<=0) goto loop_end;
+ i--;
+ if (++c[i] < lp->n[i]) break;
+ c[i] = 0;
+ }
+ }
+ loop_end:
+ ;
+ DBG(printf("]\n"));
+}
+
+static void
+ndloop_copy_from_buffer(na_buffer_copy_t *lp)
+{
+ size_t *c;
+ char *src, *buf;
+ int i;
+ int nd = lp->ndim;
+ size_t elmsz = lp->elmsz;
+ size_t buf_pos = 0;
+ DBG(size_t j);
+
+ //printf("\nfrom_buf nd=%d elmsz=%ld\n",nd,elmsz);
+ DBG(printf("<from buf> ["));
+ // zero-dimension
+ if (nd==0) {
+ src = lp->src_ptr + LITER_SRC(lp,0).pos;
+ buf = lp->buf_ptr;
+ memcpy(src,buf,elmsz);
+ DBG(for (j=0; j<elmsz/8; j++) {printf("%g,",((double*)(src))[j]);});
+ goto loop_end;
+ }
+ // initialize loop counter
+ c = ALLOCA_N(size_t, nd+1);
+ for (i=0; i<=nd; i++) c[i]=0;
+ // loop body
+ for (i=0;;) {
+ // i-th dimension
+ for (; i<nd; i++) {
+ if (LITER_SRC(lp,i).idx) {
+ LITER_SRC(lp,i+1).pos = LITER_SRC(lp,i).pos + LITER_SRC(lp,i).idx[c[i]];
+ } else {
+ LITER_SRC(lp,i+1).pos = LITER_SRC(lp,i).pos + LITER_SRC(lp,i).step*c[i];
+ }
+ }
+ src = lp->src_ptr + LITER_SRC(lp,nd).pos;
+ buf = lp->buf_ptr + buf_pos;
+ memcpy(src,buf,elmsz);
+ DBG(for (j=0; j<elmsz/8; j++) {printf("%g,",((double*)(src))[j]);});
+ buf_pos += elmsz;
+ // count up
+ for (;;) {
+ if (i<=0) goto loop_end;
+ i--;
+ if (++c[i] < lp->n[i]) break;
+ c[i] = 0;
+ }
+ }
+ loop_end:
+ DBG(printf("]\n"));
+}
+
+
+static void
+ndfunc_write_back(ndfunc_t *nf, na_md_loop_t *lp, VALUE orig_args, VALUE results)
+{
+ VALUE src, dst;
+
+ if (lp->writeback >= 0) {
+ dst = RARRAY_AREF(orig_args,lp->writeback);
+ src = RARRAY_AREF(results,0);
+ na_store(dst,src);
+ RARRAY_ASET(results,0,dst);
+ }
+}
+
+
+static VALUE
+ndloop_extract(VALUE results, ndfunc_t *nf)
+{
+ long n, i;
+ VALUE x, y;
+ narray_t *na;
+
+ // extract result objects
+ switch(nf->nout) {
+ case 0:
+ return Qnil;
+ case 1:
+ x = RARRAY_AREF(results,0);
+ if (NDF_TEST(nf,NDF_EXTRACT)) {
+ if (IsNArray(x)){
+ GetNArray(x,na);
+ if (NA_NDIM(na)==0) {
+ x = rb_funcall(x, id_extract, 0);
+ }
+ }
+ }
+ return x;
+ }
+ if (NDF_TEST(nf,NDF_EXTRACT)) {
+ n = RARRAY_LEN(results);
+ for (i=0; i<n; i++) {
+ x = RARRAY_AREF(results,i);
+ if (IsNArray(x)){
+ GetNArray(x,na);
+ if (NA_NDIM(na)==0) {
+ y = rb_funcall(x, id_extract, 0);
+ RARRAY_ASET(results,i,y);
+ }
+ }
+ }
+ }
+ return results;
+}
+
+
+static void
+loop_narray(ndfunc_t *nf, na_md_loop_t *lp);
+
+static VALUE
+ndloop_run(VALUE vlp)
+{
+ unsigned int loop_spec;
+ volatile VALUE args, orig_args, results;
+ na_md_loop_t *lp = (na_md_loop_t*)(vlp);
+ ndfunc_t *nf;
+
+ orig_args = lp->vargs;
+ nf = lp->ndfunc;
+
+ args = rb_obj_dup(orig_args);
+
+ // setup ndloop iterator with arguments
+ ndloop_init_args(nf, lp, args);
+ results = ndloop_set_output(nf, lp, args);
+
+ //if (na_debug_flag) {
+ // printf("-- ndloop_set_output --\n");
+ // print_ndloop(lp);
+ //}
+
+ // contract loop
+ if (lp->loop_func == loop_narray) {
+ ndfunc_contract_loop(lp);
+ //if (na_debug_flag) {
+ // printf("-- ndfunc_contract_loop --\n");
+ // print_ndloop(lp);
+ //}
+ }
+
+ // setup objects in which resuts are stored
+ ndfunc_set_user_loop(nf, lp);
+
+ // setup buffering during loop
+ if (lp->loop_func == loop_narray) {
+ loop_spec = ndloop_func_loop_spec(nf, lp->user.ndim);
+ ndfunc_set_bufcp(lp, loop_spec);
+ if (na_debug_flag) {
+ printf("-- ndfunc_set_bufcp --\n");
+ print_ndloop(lp);
+ }
+ }
+
+ // loop
+ (*(lp->loop_func))(nf, lp);
+
+ //if (na_debug_flag) {
+ // printf("-- after loop --\n");
+ // print_ndloop(lp);
+ //}
+
+ if (RTEST(lp->user.err_type)) {
+ rb_raise(lp->user.err_type, "error in NArray operation");
+ }
+
+ // write-back will be placed here
+ ndfunc_write_back(nf, lp, orig_args, results);
+
+ // extract result objects
+ return ndloop_extract(results, nf);
+}
+
+
+// ---------------------------------------------------------------------------
+
+static void
+loop_narray(ndfunc_t *nf, na_md_loop_t *lp)
+{
+ size_t *c;
+ int i, j;
+ int nd = lp->ndim;
+
+ if (nd<0) {
+ rb_bug("bug? lp->ndim = %d\n", lp->ndim);
+ }
+
+ if (nd==0) {
+ for (j=0; j<lp->nin; j++) {
+ if (lp->xargs[j].bufcp) {
+ //printf("copy_to_buffer j=%d\n",j);
+ ndloop_copy_to_buffer(lp->xargs[j].bufcp);
+ }
+ }
+ (*(nf->func))(&(lp->user));
+ for (j=0; j<lp->narg; j++) {
+ if (lp->xargs[j].bufcp && (lp->xargs[j].flag & NDL_WRITE)) {
+ //printf("copy_from_buffer j=%d\n",j);
+ // copy data to work buffer
+ ndloop_copy_from_buffer(lp->xargs[j].bufcp);
+ }
+ }
+ return;
+ }
+
+ // initialize loop counter
+ c = ALLOCA_N(size_t, nd+1);
+ for (i=0; i<=nd; i++) c[i]=0;
+
+ // loop body
+ for (i=0;;) {
+ // i-th dimension
+ for (; i<nd; i++) {
+ // j-th argument
+ for (j=0; j<lp->narg; j++) {
+ if (LITER(lp,i,j).idx) {
+ LITER(lp,i+1,j).pos = LITER(lp,i,j).pos + LITER(lp,i,j).idx[c[i]];
+ } else {
+ LITER(lp,i+1,j).pos = LITER(lp,i,j).pos + LITER(lp,i,j).step*c[i];
+ }
+ //printf("j=%d c[i=%d]=%lu pos=%lu\n",j,i,c[i],LITER(lp,i+1,j).pos);
+ }
+ }
+ for (j=0; j<lp->nin; j++) {
+ if (lp->xargs[j].bufcp) {
+ // copy data to work buffer
+ // cp lp->iter[j][nd..*] to lp->user.args[j].iter[0..*]
+ //printf("copy_to_buffer j=%d\n",j);
+ ndloop_copy_to_buffer(lp->xargs[j].bufcp);
+ }
+ }
+ (*(nf->func))(&(lp->user));
+ for (j=0; j<lp->narg; j++) {
+ if (lp->xargs[j].bufcp && (lp->xargs[j].flag & NDL_WRITE)) {
+ // copy data to work buffer
+ //printf("copy_from_buffer j=%d\n",j);
+ ndloop_copy_from_buffer(lp->xargs[j].bufcp);
+ }
+ }
+ if (RTEST(lp->user.err_type)) {return;}
+
+ for (;;) {
+ if (i<=0) goto loop_end;
+ i--;
+ if (++c[i] < lp->n[i]) break;
+ c[i] = 0;
+ }
+ }
+ loop_end:
+ ;
+}
+
+
+VALUE
+na_ndloop_main(ndfunc_t *nf, VALUE args, void *opt_ptr)
+{
+ unsigned int copy_flag;
+ na_md_loop_t lp;
+
+ if (na_debug_flag) print_ndfunc(nf);
+
+ // cast arguments to NArray
+ copy_flag = ndloop_cast_args(nf, args);
+
+ // allocate ndloop struct
+ ndloop_alloc(&lp, nf, args, opt_ptr, copy_flag, loop_narray);
+
+ return rb_ensure(ndloop_run, (VALUE)&lp, ndloop_release, (VALUE)&lp);
+}
+
+
+VALUE
+#ifdef HAVE_STDARG_PROTOTYPES
+na_ndloop(ndfunc_t *nf, int argc, ...)
+#else
+na_ndloop(nf, argc, va_alist)
+ ndfunc_t *nf;
+ int argc;
+ va_dcl
+#endif
+{
+ va_list ar;
+
+ int i;
+ VALUE *argv;
+ volatile VALUE args;
+
+ argv = ALLOCA_N(VALUE,argc);
+
+ va_init_list(ar, argc);
+ for (i=0; i<argc; i++) {
+ argv[i] = va_arg(ar, VALUE);
+ }
+ va_end(ar);
+
+ args = rb_ary_new4(argc, argv);
+
+ return na_ndloop_main(nf, args, NULL);
+}
+
+
+VALUE
+na_ndloop2(ndfunc_t *nf, VALUE args)
+{
+ return na_ndloop_main(nf, args, NULL);
+}
+
+VALUE
+#ifdef HAVE_STDARG_PROTOTYPES
+na_ndloop3(ndfunc_t *nf, void *ptr, int argc, ...)
+#else
+na_ndloop3(nf, ptr, argc, va_alist)
+ ndfunc_t *nf;
+ void *ptr;
+ int argc;
+ va_dcl
+#endif
+{
+ va_list ar;
+
+ int i;
+ VALUE *argv;
+ volatile VALUE args;
+
+ argv = ALLOCA_N(VALUE,argc);
+
+ va_init_list(ar, argc);
+ for (i=0; i<argc; i++) {
+ argv[i] = va_arg(ar, VALUE);
+ }
+ va_end(ar);
+
+ args = rb_ary_new4(argc, argv);
+
+ return na_ndloop_main(nf, args, ptr);
+}
+
+VALUE
+na_ndloop4(ndfunc_t *nf, void *ptr, VALUE args)
+{
+ return na_ndloop_main(nf, args, ptr);
+}
+
+//----------------------------------------------------------------------
+
+VALUE
+na_info_str(VALUE ary)
+{
+ int nd, i;
+ char tmp[32];
+ VALUE buf;
+ narray_t *na;
+
+ GetNArray(ary,na);
+ nd = na->ndim;
+
+ buf = rb_str_new2(rb_class2name(CLASS_OF(ary)));
+ if (NA_TYPE(na) == NARRAY_VIEW_T) {
+ rb_str_cat(buf,"(view)",6);
+ }
+ rb_str_cat(buf,"#shape=[",8);
+ if (nd>0) {
+ for (i=0;;) {
+ sprintf(tmp,"%"SZF"u",na->shape[i]);
+ rb_str_cat2(buf,tmp);
+ if (++i==nd) break;
+ rb_str_cat(buf,",",1);
+ }
+ }
+ rb_str_cat(buf,"]",1);
+ return buf;
+}
+
+
+//----------------------------------------------------------------------
+
+#define ncol numo_na_inspect_cols
+#define nrow numo_na_inspect_rows
+extern int ncol, nrow;
+
+static void
+loop_inspect(ndfunc_t *nf, na_md_loop_t *lp)
+{
+ int nd, i, ii;
+ size_t *c;
+ int col=0, row=0;
+ long len;
+ VALUE str;
+ na_text_func_t func = (na_text_func_t)(nf->func);
+ VALUE buf, opt;
+
+ nd = lp->ndim;
+ buf = lp->loop_opt;
+ //opt = *(VALUE*)(lp->user.opt_ptr);
+ opt = lp->user.option;
+
+ for (i=0; i<nd; i++) {
+ if (lp->n[i] == 0) {
+ rb_str_cat(buf,"[]",2);
+ return;
+ }
+ }
+
+ rb_str_cat(buf,"\n",1);
+
+ c = ALLOCA_N(size_t, nd+1);
+ for (i=0; i<=nd; i++) c[i]=0;
+
+ if (nd>0) {
+ rb_str_cat(buf,"[",1);
+ } else {
+ rb_str_cat(buf,"",0);
+ }
+
+ col = nd*2;
+ for (i=0;;) {
+ if (i<nd-1) {
+ for (ii=0; ii<i; ii++) rb_str_cat(buf," ",1);
+ for (; ii<nd-1; ii++) rb_str_cat(buf,"[",1);
+ }
+ for (; i<nd; i++) {
+ if (LITER(lp,i,0).idx) {
+ LITER(lp,i+1,0).pos = LITER(lp,i,0).pos + LITER(lp,i,0).idx[c[i]];
+ } else {
+ LITER(lp,i+1,0).pos = LITER(lp,i,0).pos + LITER(lp,i,0).step*c[i];
+ }
+ }
+ str = (*func)(LARG(lp,0).ptr, LITER(lp,i,0).pos, opt);
+
+ len = RSTRING_LEN(str) + 2;
+ if (ncol>0 && col+len > ncol-3) {
+ rb_str_cat(buf,"...",3);
+ c[i-1] = lp->n[i-1];
+ } else {
+ rb_str_append(buf, str);
+ col += len;
+ }
+ for (;;) {
+ if (i==0) goto loop_end;
+ i--;
+ if (++c[i] < lp->n[i]) break;
+ rb_str_cat(buf,"]",1);
+ c[i] = 0;
+ }
+ //line_break:
+ rb_str_cat(buf,", ",2);
+ if (i<nd-1) {
+ rb_str_cat(buf,"\n ",2);
+ col = nd*2;
+ row++;
+ if (row==nrow) {
+ rb_str_cat(buf,"...",3);
+ goto loop_end;
+ }
+ }
+ }
+ loop_end:
+ ;
+}
+
+
+VALUE
+na_ndloop_inspect(VALUE nary, na_text_func_t func, VALUE opt)
+{
+ volatile VALUE args;
+ na_md_loop_t lp;
+ VALUE buf;
+ ndfunc_arg_in_t ain[3] = {{Qnil,0},{sym_loop_opt},{sym_option}};
+ ndfunc_t nf = { (na_iter_func_t)func, NO_LOOP, 3, 0, ain, 0 };
+ //nf = ndfunc_alloc(NULL, NO_LOOP, 1, 0, Qnil);
+
+ buf = na_info_str(nary);
+
+ if (na_get_pointer(nary)==NULL) {
+ return rb_str_cat(buf,"(empty)",7);
+ }
+
+ //rb_p(args);
+ //if (na_debug_flag) print_ndfunc(&nf);
+
+ args = rb_ary_new3(3,nary,buf,opt);
+
+ // cast arguments to NArray
+ //ndloop_cast_args(nf, args);
+
+ // allocate ndloop struct
+ ndloop_alloc(&lp, &nf, args, NULL, 0, loop_inspect);
+
+ rb_ensure(ndloop_run, (VALUE)&lp, ndloop_release, (VALUE)&lp);
+
+ return buf;
+}
+
+
+//----------------------------------------------------------------------
+
+static void
+loop_store_subnarray(ndfunc_t *nf, na_md_loop_t *lp, int i0, size_t *c, VALUE a)
+{
+ int nd = lp->ndim;
+ int i, j;
+ narray_t *na;
+ int *dim_map;
+ VALUE a_type;
+
+ a_type = CLASS_OF(LARG(lp,0).value);
+ if (CLASS_OF(a) != a_type) {
+ a = rb_funcall(a_type, id_cast, 1, a);
+ }
+ GetNArray(a,na);
+ if (na->ndim != nd-i0+1) {
+ rb_raise(nary_eShapeError, "mismatched dimension of sub-narray: "
+ "nd_src=%d, nd_dst=%d", na->ndim, nd-i0+1);
+ }
+ dim_map = ALLOCA_N(int, na->ndim);
+ for (i=0; i<na->ndim; i++) {
+ dim_map[i] = lp->trans_map[i+i0];
+ //printf("dim_map[i=%d] = %d, i0=%d\n", i, dim_map[i], i0);
+ }
+ ndloop_set_stepidx(lp, 1, a, dim_map, NDL_READ);
+ LARG(lp,1).shape = &(na->shape[na->ndim-1]);
+
+ // loop body
+ for (i=i0;;) {
+ LARG(lp,1).value = Qtrue;
+ for (; i<nd; i++) {
+ for (j=0; j<2; j++) {
+ if (LITER(lp,i,j).idx) {
+ LITER(lp,i+1,j).pos = LITER(lp,i,j).pos + LITER(lp,i,j).idx[c[i]];
+ } else {
+ LITER(lp,i+1,j).pos = LITER(lp,i,j).pos + LITER(lp,i,j).step*c[i];
+ }
+ }
+ if (c[i] >= na->shape[i-i0]) {
+ LARG(lp,1).value = Qfalse;
+ }
+ }
+
+ (*(nf->func))(&(lp->user));
+
+ for (;;) {
+ if (i<=i0) goto loop_end;
+ i--; c[i]++;
+ if (c[i] < lp->n[i]) break;
+ c[i] = 0;
+ }
+ }
+ loop_end:
+ LARG(lp,1).ptr = NULL;
+}
+
+
+static void
+loop_store_rarray(ndfunc_t *nf, na_md_loop_t *lp)
+{
+ size_t *c;
+ int i;
+ VALUE *a;
+ int nd = lp->ndim;
+
+ // counter
+ c = ALLOCA_N(size_t, nd+1);
+ for (i=0; i<=nd; i++) c[i]=0;
+
+ // array at each dimension
+ a = ALLOCA_N(VALUE, nd+1);
+ a[0] = LARG(lp,1).value;
+
+ //print_ndloop(lp);
+
+ // loop body
+ for (i=0;;) {
+ for (; i<nd; i++) {
+ if (LITER(lp,i,0).idx) {
+ LITER(lp,i+1,0).pos = LITER(lp,i,0).pos + LITER(lp,i,0).idx[c[i]];
+ } else {
+ LITER(lp,i+1,0).pos = LITER(lp,i,0).pos + LITER(lp,i,0).step*c[i];
+ }
+ if (TYPE(a[i])==T_ARRAY) {
+ if (c[i] < (size_t)RARRAY_LEN(a[i])) {
+ a[i+1] = RARRAY_AREF(a[i],c[i]);
+ } else {
+ a[i+1] = Qnil;
+ }
+ } else if (IsNArray(a[i])) {
+ //printf("a[i=%d]=0x%lx\n",i,a[i]);
+ loop_store_subnarray(nf,lp,i,c,a[i]);
+ goto loop_next;
+ } else {
+ if (c[i]==0) {
+ a[i+1] = a[i];
+ } else {
+ a[i+1] = Qnil;
+ }
+ }
+ //printf("c[%d]=%lu\n",i,c[i]);
+ }
+
+ //printf("a[i=%d]=0x%lx\n",i,a[i]);
+ if (IsNArray(a[i])) {
+ loop_store_subnarray(nf,lp,i,c,a[i]);
+ } else {
+ LARG(lp,1).value = a[i];
+ (*(nf->func))(&(lp->user));
+ }
+
+ loop_next:
+ for (;;) {
+ if (i<=0) goto loop_end;
+ i--; c[i]++;
+ if (c[i] < lp->n[i]) break;
+ c[i] = 0;
+ }
+ }
+ loop_end:
+ ;
+}
+
+VALUE
+na_ndloop_store_rarray(ndfunc_t *nf, VALUE nary, VALUE rary)
+{
+ na_md_loop_t lp;
+ VALUE args;
+
+ //rb_p(args);
+ if (na_debug_flag) print_ndfunc(nf);
+
+ args = rb_assoc_new(nary,rary);
+
+ // cast arguments to NArray
+ //ndloop_cast_args(nf, args);
+
+ // allocate ndloop struct
+ ndloop_alloc(&lp, nf, args, NULL, 0, loop_store_rarray);
+
+ return rb_ensure(ndloop_run, (VALUE)&lp, ndloop_release, (VALUE)&lp);
+}
+
+
+VALUE
+na_ndloop_store_rarray2(ndfunc_t *nf, VALUE nary, VALUE rary, VALUE opt)
+{
+ na_md_loop_t lp;
+ VALUE args;
+
+ //rb_p(args);
+ if (na_debug_flag) print_ndfunc(nf);
+
+ //args = rb_assoc_new(rary,nary);
+ args = rb_ary_new3(3,nary,rary,opt);
+
+ // cast arguments to NArray
+ //ndloop_cast_args(nf, args);
+
+ // allocate ndloop struct
+ ndloop_alloc(&lp, nf, args, NULL, 0, loop_store_rarray);
+
+ return rb_ensure(ndloop_run, (VALUE)&lp, ndloop_release, (VALUE)&lp);
+}
+
+
+//----------------------------------------------------------------------
+
+static void
+loop_narray_to_rarray(ndfunc_t *nf, na_md_loop_t *lp)
+{
+ size_t *c;
+ int i;
+ //int nargs = nf->narg + nf->nres;
+ int nd = lp->ndim;
+ VALUE *a;
+ volatile VALUE a0;
+
+ // alloc counter
+ c = ALLOCA_N(size_t, nd+1);
+ for (i=0; i<=nd; i++) c[i]=0;
+ //c[i]=1; // for zero-dim
+ //fprintf(stderr,"in loop_narray_to_rarray, nd=%d\n",nd);
+
+ a = ALLOCA_N(VALUE, nd+1);
+ a[0] = a0 = lp->loop_opt;
+
+ // loop body
+ for (i=0;;) {
+ for (; i<nd; i++) {
+ if (LITER(lp,i,0).idx) {
+ LITER(lp,i+1,0).pos = LITER(lp,i,0).pos + LITER(lp,i,0).idx[c[i]];
+ } else {
+ LITER(lp,i+1,0).pos = LITER(lp,i,0).pos + LITER(lp,i,0).step*c[i];
+ }
+ if (c[i]==0) {
+ a[i+1] = rb_ary_new2(lp->n[i]);
+ rb_ary_push(a[i],a[i+1]);
+ }
+ }
+
+ //lp->user.info = a[i];
+ LARG(lp,1).value = a[i];
+ (*(nf->func))(&(lp->user));
+
+ for (;;) {
+ if (i<=0) goto loop_end;
+ i--;
+ if (++c[i] < lp->n[i]) break;
+ c[i] = 0;
+ }
+ }
+ loop_end:
+ ;
+}
+
+VALUE
+na_ndloop_cast_narray_to_rarray(ndfunc_t *nf, VALUE nary, VALUE fmt)
+{
+ na_md_loop_t lp;
+ VALUE args, a0;
+
+ //rb_p(args);
+ if (na_debug_flag) print_ndfunc(nf);
+
+ a0 = rb_ary_new();
+ args = rb_ary_new3(3,nary,a0,fmt);
+
+ // cast arguments to NArray
+ //ndloop_cast_args(nf, args);
+
+ // allocate ndloop struct
+ ndloop_alloc(&lp, nf, args, NULL, 0, loop_narray_to_rarray);
+
+ rb_ensure(ndloop_run, (VALUE)&lp, ndloop_release, (VALUE)&lp);
+ return RARRAY_AREF(a0,0);
+}
+
+
+//----------------------------------------------------------------------
+
+static void
+loop_narray_with_index(ndfunc_t *nf, na_md_loop_t *lp)
+{
+ size_t *c;
+ int i,j;
+ int nd = lp->ndim;
+
+ // pass total ndim to iterator
+ lp->user.ndim += nd;
+
+ // alloc counter
+ lp->user.opt_ptr = c = ALLOCA_N(size_t, nd+1);
+ for (i=0; i<=nd; i++) c[i]=0;
+
+ // loop body
+ for (i=0;;) {
+ for (; i<nd; i++) {
+ // j-th argument
+ for (j=0; j<lp->narg; j++) {
+ if (LITER(lp,i,j).idx) {
+ LITER(lp,i+1,j).pos = LITER(lp,i,j).pos + LITER(lp,i,j).idx[c[i]];
+ } else {
+ LITER(lp,i+1,j).pos = LITER(lp,i,j).pos + LITER(lp,i,j).step*c[i];
+ }
+ //printf("j=%d c[i=%d]=%lu pos=%lu\n",j,i,c[i],LITER(lp,i+1,j).pos);
+ }
+ }
+
+ (*(nf->func))(&(lp->user));
+
+ for (;;) {
+ if (i<=0) goto loop_end;
+ i--;
+ if (++c[i] < lp->n[i]) break;
+ c[i] = 0;
+ }
+ }
+ loop_end:
+ ;
+}
+
+
+VALUE
+#ifdef HAVE_STDARG_PROTOTYPES
+na_ndloop_with_index(ndfunc_t *nf, int argc, ...)
+#else
+na_ndloop(nf, argc, va_alist)
+ ndfunc_t *nf;
+ int argc;
+ va_dcl
+#endif
+{
+ va_list ar;
+
+ int i;
+ VALUE *argv;
+ volatile VALUE args;
+ na_md_loop_t lp;
+
+ argv = ALLOCA_N(VALUE,argc);
+
+ va_init_list(ar, argc);
+ for (i=0; i<argc; i++) {
+ argv[i] = va_arg(ar, VALUE);
+ }
+ va_end(ar);
+
+ args = rb_ary_new4(argc, argv);
+
+ //return na_ndloop_main(nf, args, NULL);
+ if (na_debug_flag) print_ndfunc(nf);
+
+ // cast arguments to NArray
+ //copy_flag = ndloop_cast_args(nf, args);
+
+ // allocate ndloop struct
+ ndloop_alloc(&lp, nf, args, 0, 0, loop_narray_with_index);
+
+ return rb_ensure(ndloop_run, (VALUE)&lp, ndloop_release, (VALUE)&lp);
+}
+
+
+void
+Init_nary_ndloop()
+{
+ id_cast = rb_intern("cast");
+ id_extract = rb_intern("extract");
+}
diff --git a/ext/numo/narray/numo/compat.h b/ext/numo/narray/numo/compat.h
new file mode 100644
index 0000000..8a6907a
--- /dev/null
+++ b/ext/numo/narray/numo/compat.h
@@ -0,0 +1,23 @@
+#ifndef COMPAT_H
+#define COMPAT_H
+
+#if !defined RSTRING_LEN
+#define RSTRING_LEN(a) RSTRING(a)->len
+#endif
+#if !defined RSTRING_PTR
+#define RSTRING_PTR(a) RSTRING(a)->ptr
+#endif
+#if !defined RARRAY_LEN
+#define RARRAY_LEN(a) RARRAY(a)->len
+#endif
+#if !defined RARRAY_PTR
+#define RARRAY_PTR(a) RARRAY(a)->ptr
+#endif
+#if !defined RARRAY_AREF
+#define RARRAY_AREF(a,i) RARRAY_PTR(a)[i]
+#endif
+#if !defined RARRAY_ASET
+#define RARRAY_ASET(a,i,v) (RARRAY_PTR(a)[i] = v)
+#endif
+
+#endif /* ifndef COMPAT_H */
diff --git a/ext/numo/narray/numo/intern.h b/ext/numo/narray/numo/intern.h
new file mode 100644
index 0000000..3bcb246
--- /dev/null
+++ b/ext/numo/narray/numo/intern.h
@@ -0,0 +1,109 @@
+/*
+ intern.h
+ Numerical Array Extension for Ruby
+ (C) Copyright 1999-2017 by Masahiro TANAKA
+*/
+#ifndef INTERN_H
+#define INTERN_H
+
+#define rb_narray_new nary_new
+VALUE nary_new(VALUE elem, int ndim, size_t *shape);
+#define rb_narray_view_new nary_view_new
+VALUE nary_view_new(VALUE elem, int ndim, size_t *shape);
+#define rb_narray_debug_info nary_debug_info
+VALUE nary_debug_info(VALUE);
+
+#define na_make_view nary_make_view
+VALUE nary_make_view(VALUE self);
+
+#define na_s_allocate nary_s_allocate
+VALUE nary_s_allocate(VALUE klass);
+#define na_s_allocate_view nary_s_allocate_view
+VALUE nary_s_allocate_view(VALUE klass);
+#define na_s_new_like nary_s_new_like
+VALUE nary_s_new_like(VALUE type, VALUE obj);
+
+void na_alloc_shape(narray_t *na, int ndim);
+void na_array_to_internal_shape(VALUE self, VALUE ary, size_t *shape);
+void na_index_arg_to_internal_order(int argc, VALUE *argv, VALUE self);
+void na_setup_shape(narray_t *na, int ndim, size_t *shape);
+
+#define na_get_elmsz nary_element_stride
+//#define na_element_stride nary_element_stride
+unsigned int nary_element_stride(VALUE nary);
+#define na_dtype_elmsz nary_dtype_element_stride
+size_t nary_dtype_element_stride(VALUE klass);
+
+#define na_get_pointer nary_get_pointer
+char *nary_get_pointer(VALUE);
+#define na_get_pointer_for_write nary_get_pointer_for_write
+char *nary_get_pointer_for_write(VALUE);
+#define na_get_pointer_for_read nary_get_pointer_for_read
+char *nary_get_pointer_for_read(VALUE);
+#define na_get_pointer_for_read_write nary_get_pointer_for_read_write
+char *nary_get_pointer_for_read_write(VALUE);
+#define na_get_offset nary_get_offset
+size_t nary_get_offset(VALUE self);
+
+#define na_copy_flags nary_copy_flags
+void nary_copy_flags(VALUE src, VALUE dst);
+
+#define na_check_ladder nary_check_ladder
+VALUE nary_check_ladder(VALUE self, int start_dim);
+#define na_check_contiguous nary_check_contiguous
+VALUE nary_check_contiguous(VALUE self);
+
+#define na_flatten_dim nary_flatten_dim
+VALUE nary_flatten_dim(VALUE self, int sd);
+
+#define na_flatten nary_flatten
+VALUE nary_flatten(VALUE);
+
+#define na_copy nary_dup
+VALUE nary_dup(VALUE);
+
+#define na_store nary_store
+VALUE nary_store(VALUE self, VALUE src);
+
+#define na_upcast numo_na_upcast
+VALUE numo_na_upcast(VALUE type1, VALUE type2);
+
+void na_release_lock(VALUE); // currently do nothing
+
+// used in reduce methods
+#define na_reduce_dimension nary_reduce_dimension
+VALUE nary_reduce_dimension(int argc, VALUE *argv, int naryc, VALUE *naryv,
+ ndfunc_t *ndf, na_iter_func_t nan_iter);
+
+#define na_reduce_options nary_reduce_options
+VALUE nary_reduce_options(VALUE axes, VALUE *opts, int naryc, VALUE *naryv,
+ ndfunc_t *ndf);
+
+// ndloop
+VALUE na_ndloop(ndfunc_t *nf, int argc, ...);
+VALUE na_ndloop2(ndfunc_t *nf, VALUE args);
+VALUE na_ndloop3(ndfunc_t *nf, void *ptr, int argc, ...);
+VALUE na_ndloop4(ndfunc_t *nf, void *ptr, VALUE args);
+
+VALUE na_ndloop_cast_narray_to_rarray(ndfunc_t *nf, VALUE nary, VALUE fmt);
+VALUE na_ndloop_store_rarray(ndfunc_t *nf, VALUE nary, VALUE rary);
+VALUE na_ndloop_store_rarray2(ndfunc_t *nf, VALUE nary, VALUE rary, VALUE opt);
+VALUE na_ndloop_inspect(VALUE nary, na_text_func_t func, VALUE opt);
+VALUE na_ndloop_with_index(ndfunc_t *nf, int argc, ...);
+
+#define na_info_str nary_info_str
+VALUE nary_info_str(VALUE);
+
+#define na_test_reduce nary_test_reduce
+bool nary_test_reduce(VALUE reduce, int dim);
+
+void nary_step_array_index(VALUE self, size_t ary_size, size_t *plen, ssize_t *pbeg, ssize_t *pstep);
+void nary_step_sequence(VALUE self, size_t *plen, double *pbeg, double *pstep);
+
+// used in aref, aset
+#define na_get_result_dimension nary_get_result_dimension
+int nary_get_result_dimension(VALUE self, int argc, VALUE *argv, ssize_t stride, size_t *pos_idx);
+#define na_aref_main nary_aref_main
+VALUE nary_aref_main(int nidx, VALUE *idx, VALUE self, int keep_dim, int nd);
+
+#endif /* ifndef INTERN_H */
diff --git a/ext/numo/narray/numo/narray.h b/ext/numo/narray/numo/narray.h
new file mode 100644
index 0000000..7f7ebf2
--- /dev/null
+++ b/ext/numo/narray/numo/narray.h
@@ -0,0 +1,429 @@
+/*
+ narray.h
+ Numerical Array Extension for Ruby
+ (C) Copyright 1999-2017 by Masahiro TANAKA
+*/
+#ifndef NARRAY_H
+#define NARRAY_H
+
+#if defined(__cplusplus)
+extern "C" {
+#if 0
+} /* satisfy cc-mode */
+#endif
+#endif
+
+#define NARRAY_VERSION "0.9.0.7"
+#define NARRAY_VERSION_CODE 907
+
+#include <math.h>
+#include "numo/compat.h"
+#include "numo/template.h"
+#include "numo/extconf.h"
+
+#ifdef HAVE_STDBOOL_H
+# include <stdbool.h>
+#endif
+
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifndef HAVE_U_INT8_T
+# ifdef HAVE_UINT8_T
+ typedef uint8_t u_int8_t;
+# endif
+#endif
+
+#ifndef HAVE_U_INT16_T
+# ifdef HAVE_UINT16_T
+ typedef uint16_t u_int16_t;
+# endif
+#endif
+
+#ifndef HAVE_U_INT32_T
+# ifdef HAVE_UINT32_T
+ typedef uint32_t u_int32_t;
+# endif
+#endif
+
+#ifndef HAVE_U_INT64_T
+# ifdef HAVE_UINT64_T
+ typedef uint64_t u_int64_t;
+# endif
+#endif
+
+#define SZF PRI_SIZE_PREFIX // defined in ruby.h
+
+#if SIZEOF_LONG==8
+# define NUM2INT64(x) NUM2LONG(x)
+# define INT642NUM(x) LONG2NUM(x)
+# define NUM2UINT64(x) NUM2ULONG(x)
+# define UINT642NUM(x) ULONG2NUM(x)
+# ifndef PRId64
+# define PRId64 "ld"
+# endif
+# ifndef PRIu64
+# define PRIu64 "lu"
+# endif
+#elif SIZEOF_LONG_LONG==8
+# define NUM2INT64(x) NUM2LL(x)
+# define INT642NUM(x) LL2NUM(x)
+# define NUM2UINT64(x) NUM2ULL(x)
+# define UINT642NUM(x) ULL2NUM(x)
+# ifndef PRId64
+# define PRId64 "lld"
+# endif
+# ifndef PRIu64
+# define PRIu64 "llu"
+# endif
+#endif
+
+#if SIZEOF_LONG==4
+# define NUM2INT32(x) NUM2LONG(x)
+# define INT322NUM(x) LONG2NUM(x)
+# define NUM2UINT32(x) NUM2ULONG(x)
+# define UINT322NUM(x) ULONG2NUM(x)
+# ifndef PRId32
+# define PRId32 "ld"
+# endif
+# ifndef PRIu32
+# define PRIu32 "lu"
+# endif
+#elif SIZEOF_INT==4
+# define NUM2INT32(x) NUM2INT(x)
+# define INT322NUM(x) INT2NUM(x)
+# define NUM2UINT32(x) NUM2UINT(x)
+# define UINT322NUM(x) UINT2NUM(x)
+# ifndef PRId32
+# define PRId32 "d"
+# endif
+# ifndef PRIu32
+# define PRIu32 "u"
+# endif
+#endif
+
+#ifndef HAVE_TYPE_BOOL
+ typedef int bool;
+#endif
+#ifndef FALSE /* in case these macros already exist */
+# define FALSE 0 /* values of bool */
+#endif
+#ifndef TRUE
+# define TRUE 1
+#endif
+
+typedef struct { float dat[2]; } scomplex;
+typedef struct { double dat[2]; } dcomplex;
+typedef int fortran_integer;
+
+#define REAL(x) ((x).dat[0])
+#define IMAG(x) ((x).dat[1])
+
+extern int na_debug_flag;
+
+#ifndef NARRAY_C
+extern VALUE numo_cNArray;
+extern VALUE rb_mNumo;
+extern VALUE nary_eCastError;
+extern VALUE nary_eShapeError;
+extern VALUE nary_eOperationError;
+extern VALUE nary_eDimensionError;
+extern const rb_data_type_t na_data_type;
+
+//EXTERN const int na_sizeof[NA_NTYPES+1];
+#endif
+
+#define cNArray numo_cNArray
+#define mNumo rb_mNumo
+//#define na_upcast(x,y) numo_na_upcast(x,y)
+
+/* global variables within this module */
+extern VALUE numo_cBit;
+extern VALUE numo_cDFloat;
+extern VALUE numo_cSFloat;
+extern VALUE numo_cDComplex;
+extern VALUE numo_cSComplex;
+extern VALUE numo_cInt64;
+extern VALUE numo_cInt32;
+extern VALUE numo_cInt16;
+extern VALUE numo_cInt8;
+extern VALUE numo_cUInt64;
+extern VALUE numo_cUInt32;
+extern VALUE numo_cUInt16;
+extern VALUE numo_cUInt8;
+extern VALUE numo_cRObject;
+extern VALUE na_cStep;
+#ifndef HAVE_RB_CCOMPLEX
+extern VALUE rb_cComplex;
+#endif
+
+extern VALUE sym_reduce;
+extern VALUE sym_option;
+extern VALUE sym_loop_opt;
+extern VALUE sym_init;
+
+#define NARRAY_DATA_T 0x1
+#define NARRAY_VIEW_T 0x2
+#define NARRAY_FILEMAP_T 0x3
+
+typedef struct RNArray {
+ unsigned char ndim; // # of dimensions
+ unsigned char type;
+ unsigned char flag[2]; // flags
+ unsigned short elmsz; // element size
+ size_t size; // # of total elements
+ size_t *shape; // # of elements for each dimension
+ VALUE reduce;
+} narray_t;
+
+
+typedef struct RNArrayData {
+ narray_t base;
+ char *ptr;
+} narray_data_t;
+
+
+typedef union {
+ ssize_t stride;
+ size_t *index;
+} stridx_t;
+
+typedef struct RNArrayView {
+ narray_t base;
+ VALUE data; // data object
+ size_t offset; // offset of start point from data pointer
+ // :in units of elm.unit_bits
+ // address_unit pointer_unit access_unit data_unit
+ // elm.step_unit = elm.bit_size / elm.access_unit
+ // elm.step_unit = elm.size_bits / elm.unit_bits
+ stridx_t *stridx; // stride or indices of data pointer for each dimension
+} narray_view_t;
+
+
+// filemap is unimplemented
+typedef struct RNArrayFileMap {
+ narray_t base;
+ char *ptr;
+#ifdef WIN32
+ HANDLE hFile;
+ HANDLE hMap;
+#else // POSIX mmap
+ int prot;
+ int flag;
+#endif
+} narray_filemap_t;
+
+
+// this will be revised in future.
+typedef struct {
+ unsigned int element_bits;
+ unsigned int element_bytes;
+ unsigned int element_stride;
+} narray_type_info_t;
+
+
+static inline narray_t *
+na_get_narray_t(VALUE obj)
+{
+ narray_t *na;
+
+ Check_TypedStruct(obj,&na_data_type);
+ na = (narray_t*)DATA_PTR(obj);
+ return na;
+}
+
+static inline narray_t *
+_na_get_narray_t(VALUE obj, unsigned char na_type)
+{
+ narray_t *na;
+
+ Check_TypedStruct(obj,&na_data_type);
+ na = (narray_t*)DATA_PTR(obj);
+ if (na->type != na_type) {
+ rb_bug("unknown type 0x%x (0x%x given)", na_type, na->type);
+ }
+ return na;
+}
+
+#define na_get_narray_data_t(obj) (narray_data_t*)_na_get_narray_t(obj,NARRAY_DATA_T)
+#define na_get_narray_view_t(obj) (narray_view_t*)_na_get_narray_t(obj,NARRAY_VIEW_T)
+#define na_get_narray_filemap_t(obj) (narray_filemap_t*)_na_get_narray_t(obj,NARRAY_FILEMAP_T)
+
+#define GetNArray(obj,var) TypedData_Get_Struct(obj, narray_t, &na_data_type, var)
+#define GetNArrayView(obj,var) TypedData_Get_Struct(obj, narray_view_t, &na_data_type, var)
+#define GetNArrayData(obj,var) TypedData_Get_Struct(obj, narray_data_t, &na_data_type, var)
+
+#define SDX_IS_STRIDE(x) ((x).stride&0x1)
+#define SDX_IS_INDEX(x) (!SDX_IS_STRIDE(x))
+#define SDX_GET_STRIDE(x) ((x).stride>>1)
+#define SDX_GET_INDEX(x) ((x).index)
+
+#define SDX_SET_STRIDE(x,s) ((x).stride=((s)<<1)|0x1)
+#define SDX_SET_INDEX(x,idx) ((x).index=idx)
+
+#define RNARRAY(val) ((narray_t*)DATA_PTR(val))
+#define RNARRAY_DATA(val) ((narray_data_t*)DATA_PTR(val))
+#define RNARRAY_VIEW(val) ((narray_view_t*)DATA_PTR(val))
+#define RNARRAY_FILEMAP(val) ((narray_filemap_t*)DATA_PTR(val))
+
+#define RNARRAY_NDIM(val) (RNARRAY(val)->ndim)
+#define RNARRAY_TYPE(val) (RNARRAY(val)->type)
+#define RNARRAY_FLAG(val) (RNARRAY(val)->flag)
+#define RNARRAY_SIZE(val) (RNARRAY(val)->size)
+#define RNARRAY_SHAPE(val) (RNARRAY(val)->shape)
+#define RNARRAY_REDUCE(val) (RNARRAY(val)->reduce)
+
+#define RNARRAY_DATA_PTR(val) (RNARRAY_DATA(val)->ptr)
+#define RNARRAY_VIEW_DATA(val) (RNARRAY_VIEW(val)->data)
+#define RNARRAY_VIEW_OFFSET(val) (RNARRAY_VIEW(val)->offset)
+#define RNARRAY_VIEW_STRIDX(val) (RNARRAY_VIEW(val)->stridx)
+
+#define NA_NDIM(na) (((narray_t*)na)->ndim)
+#define NA_TYPE(na) (((narray_t*)na)->type)
+#define NA_SIZE(na) (((narray_t*)na)->size)
+#define NA_SHAPE(na) (((narray_t*)na)->shape)
+#define NA_REDUCE(na) (((narray_t*)na)->reduce)
+
+#define NA_FLAG(obj) (na_get_narray_t(obj)->flag)
+#define NA_FLAG0(obj) (NA_FLAG(obj)[0])
+#define NA_FLAG1(obj) (NA_FLAG(obj)[1])
+
+#define NA_DATA(na) ((narray_data_t*)(na))
+#define NA_VIEW(na) ((narray_view_t*)(na))
+#define NA_DATA_PTR(na) (NA_DATA(na)->ptr)
+#define NA_VIEW_DATA(na) (NA_VIEW(na)->data)
+#define NA_VIEW_OFFSET(na) (NA_VIEW(na)->offset)
+#define NA_VIEW_STRIDX(na) (NA_VIEW(na)->stridx)
+
+#define NA_IS_INDEX_AT(na,i) (SDX_IS_INDEX(NA_VIEW_STRIDX(na)[i]))
+#define NA_IS_STRIDE_AT(na,i) (SDX_IS_STRIDE(NA_VIEW_STRIDX(na)[i]))
+#define NA_INDEX_AT(na,i) (SDX_GET_INDEX(NA_VIEW_STRIDX(na)[i]))
+#define NA_STRIDE_AT(na,i) (SDX_GET_STRIDE(NA_VIEW_STRIDX(na)[i]))
+
+#define NA_FILEMAP_PTR(na) (((narray_filemap_t*)na)->ptr)
+
+
+#define NA_FL0_TEST(x,f) (NA_FLAG0(x)&(f))
+#define NA_FL1_TEST(x,f) (NA_FLAG1(x)&(f))
+
+#define NA_FL0_SET(x,f) do {NA_FLAG0(x) |= (f);} while(0)
+#define NA_FL1_SET(x,f) do {NA_FLAG1(x) |= (f);} while(0)
+
+#define NA_FL0_UNSET(x,f) do {NA_FLAG0(x) &= ~(f);} while(0)
+#define NA_FL1_UNSET(x,f) do {NA_FLAG1(x) &= ~(f);} while(0)
+
+#define NA_FL0_REVERSE(x,f) do {NA_FLAG0(x) ^= (f);} while(0)
+#define NA_FL1_REVERSE(x,f) do {NA_FLAG1(x) ^= (f);} while(0)
+
+
+/* FLAGS
+ - row-major / column-major
+ - Overwrite or not
+ - byteswapp
+ - Extensible?
+ - matrix or not
+*/
+
+#define NA_FL0_BIG_ENDIAN (0x1<<0)
+#define NA_FL0_COLUMN_MAJOR (0x1<<1)
+#define NA_FL1_LOCK (0x1<<0)
+#define NA_FL1_INPLACE (0x1<<1)
+
+#define TEST_COLUMN_MAJOR(x) NA_FL0_TEST(x,NA_FL0_COLUMN_MAJOR)
+#define SET_COLUMN_MAJOR(x) NA_FL0_SET(x,NA_FL0_COLUMN_MAJOR)
+#define UNSET_COLUMN_MAJOR(x) NA_FL0_UNSET(x,NA_FL0_COLUMN_MAJOR)
+
+#define TEST_ROW_MAJOR(x) (!TEST_COLUMN_MAJOR(x))
+#define SET_ROW_MAJOR(x) UNSET_COLUMN_MAJOR(x)
+#define UNSET_ROW_MAJOR(x) SET_COLUMN_MAJOR(x)
+
+#define TEST_BIG_ENDIAN(x) NA_FL0_TEST(x,NA_FL0_BIG_ENDIAN)
+#define SET_BIG_ENDIAN(x) NA_FL0_SET(x,NA_FL0_BIG_ENDIAN)
+#define UNSET_BIG_ENDIAN(x) NA_FL0_UNSET(x,NA_FL0_BIG_ENDIAN)
+
+#define TEST_LITTLE_ENDIAN(x) (!TEST_BIG_ENDIAN(x))
+#define SET_LITTLE_ENDIAN(x) UNSET_BIG_ENDIAN(x)
+#define UNSET_LITTLE_ENDIAN(x) SET_BIG_ENDIAN(x)
+
+#define REVERSE_ENDIAN(x) NA_FL0_REVERSE((x),NA_FL0_BIG_ENDIAN)
+
+#define TEST_LOCK(x) NA_FL1_TEST(x,NA_FL1_LOCK)
+#define SET_LOCK(x) NA_FL1_SET(x,NA_FL1_LOCK)
+#define UNSET_LOCK(x) NA_FL1_UNSET(x,NA_FL1_LOCK)
+
+#define TEST_INPLACE(x) NA_FL1_TEST(x,NA_FL1_INPLACE)
+#define SET_INPLACE(x) NA_FL1_SET(x,NA_FL1_INPLACE)
+#define UNSET_INPLACE(x) NA_FL1_UNSET(x,NA_FL1_INPLACE)
+
+#ifdef DYNAMIC_ENDIAN
+// not supported
+#else
+#ifdef WORDS_BIGENDIAN
+#define TEST_HOST_ORDER(x) TEST_BIG_ENDIAN(x)
+#define SET_HOST_ORDER(x) SET_BIG_ENDIAN(x)
+#define UNSET_HOST_ORDER(x) UNSET_BIG_ENDIAN(x)
+#define TEST_BYTE_SWAPPED(x) TEST_LITTLE_ENDIAN(x)
+#define SET_BYTE_SWAPPED(x) SET_LITTLE_ENDIAN(x)
+#define UNSET_BYTE_SWAPPED(x) UNSET_LITTLE_ENDIAN(x)
+#define NA_FL0_INIT NA_FL0_BIG_ENDIAN
+#else // LITTLE ENDIAN
+#define TEST_HOST_ORDER(x) TEST_LITTLE_ENDIAN(x)
+#define SET_HOST_ORDER(x) SET_LITTLE_ENDIAN(x)
+#define UNSET_HOST_ORDER(x) UNSET_LITTLE_ENDIAN(x)
+#define TEST_BYTE_SWAPPED(x) TEST_BIG_ENDIAN(x)
+#define SET_BYTE_SWAPPED(x) SET_BIG_ENDIAN(x)
+#define UNSET_BYTE_SWAPPED(x) UNSET_BIG_ENDIAN(x)
+#define NA_FL0_INIT 0
+#endif
+#endif
+#define NA_FL1_INIT 0
+
+
+#define IsNArray(obj) (rb_obj_is_kind_of(obj,cNArray)==Qtrue)
+
+#define DEBUG_PRINT(v) puts(StringValueCStr(rb_funcall(v,rb_intern("inspect"),0)))
+
+#define NA_IsNArray(obj) \
+ (rb_obj_is_kind_of(obj,cNArray)==Qtrue)
+#define NA_IsArray(obj) \
+ (TYPE(obj)==T_ARRAY || rb_obj_is_kind_of(obj,cNArray)==Qtrue)
+
+#define NUM2REAL(v) NUM2DBL( rb_funcall((v),na_id_real,0) )
+#define NUM2IMAG(v) NUM2DBL( rb_funcall((v),na_id_imag,0) )
+
+#define NA_MAX_DIMENSION (int)(sizeof(VALUE)*8-2)
+#define NA_MAX_ELMSZ 65535
+
+typedef unsigned int BIT_DIGIT;
+//#define BYTE_BIT_DIGIT sizeof(BIT_DIGIT)
+#define NB (sizeof(BIT_DIGIT)*8)
+#define BALL (~(BIT_DIGIT)0)
+#define SLB(n) (((n)==NB)?~(BIT_DIGIT)0:(~(~(BIT_DIGIT)0<<(n))))
+
+#define ELEMENT_BIT_SIZE "ELEMENT_BIT_SIZE"
+#define ELEMENT_BYTE_SIZE "ELEMENT_BYTE_SIZE"
+#define CONTIGUOUS_STRIDE "CONTIGUOUS_STRIDE"
+
+
+#ifdef RUBY_INTEGER_UNIFICATION
+#define IS_INTEGER_CLASS(c) ((c)==rb_cInteger)
+#else
+#define IS_INTEGER_CLASS(c) ((c)==rb_cFixnum||(c)==rb_cBignum)
+#endif
+
+#include "numo/ndloop.h"
+#include "numo/intern.h"
+
+#if defined(__cplusplus)
+#if 0
+{ /* satisfy cc-mode */
+#endif
+} /* extern "C" { */
+#endif
+
+#endif /* ifndef NARRAY_H */
diff --git a/ext/numo/narray/numo/ndloop.h b/ext/numo/narray/numo/ndloop.h
new file mode 100644
index 0000000..0b387b4
--- /dev/null
+++ b/ext/numo/narray/numo/ndloop.h
@@ -0,0 +1,94 @@
+/*
+ ndloop.h
+ Numerical Array Extension for Ruby
+ (C) Copyright 1999-2017 by Masahiro TANAKA
+*/
+#ifndef NDLOOP_H
+#define NDLOOP_H
+
+typedef struct NA_LOOP_ITER {
+ ssize_t pos; // - required for each dimension.
+ ssize_t step;
+ size_t *idx;
+} na_loop_iter_t;
+
+typedef struct NA_LOOP_ARGS {
+ VALUE value;
+ ssize_t elmsz;
+ char *ptr;
+ //char *buf_ptr; //
+ int ndim; // required for each argument.
+ // ssize_t pos; - not required here.
+ size_t *shape;
+ na_loop_iter_t *iter; // moved from na_loop_t
+} na_loop_args_t;
+
+// pass this structure to user iterator
+typedef struct NA_LOOP {
+ int narg;
+ int ndim; // n of user dimention - required for each iterator.
+ size_t *n; // n of elements for each dim (=shape)
+ na_loop_args_t *args; // for each arg
+ VALUE option;
+ void *opt_ptr;
+ VALUE err_type;
+} na_loop_t;
+
+
+// ------------------ ndfunc -------------------------------------------
+
+#define NDF_HAS_LOOP (1<<0) // x[i]
+#define NDF_STRIDE_LOOP (1<<1) // *(x+stride*i)
+#define NDF_INDEX_LOOP (1<<2) // *(x+idx[i])
+#define NDF_KEEP_DIM (1<<3)
+#define NDF_INPLACE (1<<4)
+#define NDF_ACCEPT_BYTESWAP (1<<5)
+
+#define NDF_FLAT_REDUCE (1<<6)
+#define NDF_EXTRACT (1<<7)
+#define NDF_CUM (1<<8)
+
+#define FULL_LOOP (NDF_HAS_LOOP|NDF_STRIDE_LOOP|NDF_INDEX_LOOP|NDF_INPLACE)
+#define FULL_LOOP_NIP (NDF_HAS_LOOP|NDF_STRIDE_LOOP|NDF_INDEX_LOOP)
+#define STRIDE_LOOP (NDF_HAS_LOOP|NDF_STRIDE_LOOP|NDF_INPLACE)
+#define STRIDE_LOOP_NIP (NDF_HAS_LOOP|NDF_STRIDE_LOOP)
+#define NO_LOOP 0
+
+#define OVERWRITE Qtrue // used for CASTABLE(t)
+
+#define NDF_TEST(nf,fl) ((nf)->flag & (fl))
+#define NDF_SET(nf,fl) {(nf)->flag |= (fl);}
+
+#define NDF_ARG_READ_ONLY 1
+#define NDF_ARG_WRITE_ONLY 2
+#define NDF_ARG_READ_WRITE 3
+
+// type of user function
+typedef void (*na_iter_func_t) _((na_loop_t *const));
+typedef VALUE (*na_text_func_t) _((char *ptr, size_t pos, VALUE opt));
+//typedef void (*) void (*loop_func)(ndfunc_t*, na_md_loop_t*))
+
+
+typedef struct NDF_ARG_IN {
+ VALUE type; // argument types
+ int dim; // # of dimension of argument handled by user function
+ // if dim==-1, reduce dimension
+} ndfunc_arg_in_t;
+
+typedef struct NDF_ARG_OUT {
+ VALUE type; // argument types
+ int dim; // # of dimension of argument handled by user function
+ size_t *shape;
+} ndfunc_arg_out_t;
+
+// spec of user function
+typedef struct NDFUNCTION {
+ na_iter_func_t func; // user function
+ unsigned int flag; // what kind of loop user function supports
+ int nin; // # of arguments
+ int nout; // # of results
+ ndfunc_arg_in_t *ain; // spec of input arguments
+ ndfunc_arg_out_t *aout; // spec of output result
+} ndfunc_t;
+
+#endif /* NDLOOP_H */
diff --git a/ext/numo/narray/numo/template.h b/ext/numo/narray/numo/template.h
new file mode 100644
index 0000000..2fd6e0e
--- /dev/null
+++ b/ext/numo/narray/numo/template.h
@@ -0,0 +1,136 @@
+/*
+ template.h
+ Numerical Array Extension for Ruby
+ (C) Copyright 1999-2017 by Masahiro TANAKA
+*/
+#ifndef TEMPLATE_H
+#define TEMPLATE_H
+
+#define INIT_COUNTER( lp, c ) \
+ { c = (lp)->n[0]; }
+
+#define NDL_CNT(lp) ((lp)->n[0])
+#define NDL_PTR(lp,i) ((lp)->args[i].ptr + (lp)->args[i].iter[0].pos)
+#define NDL_STEP(lp,i) ((lp)->args[i].iter[0].step)
+#define NDL_IDX(lp,i) ((lp)->args[i].iter[0].idx)
+#define NDL_ESZ(lp,i) ((lp)->args[i].elmsz)
+#define NDL_SHAPE(lp,i) ((lp)->args[i].shape)
+
+#define INIT_PTR( lp, i, pt, st ) \
+ { \
+ pt = ((lp)->args[i]).ptr + ((lp)->args[i].iter[0]).pos; \
+ st = ((lp)->args[i].iter[0]).step; \
+ }
+
+#define INIT_PTR_IDX( lp, i, pt, st, id ) \
+ { \
+ pt = ((lp)->args[i]).ptr + ((lp)->args[i].iter[0]).pos; \
+ st = ((lp)->args[i].iter[0]).step; \
+ id = ((lp)->args[i].iter[0]).idx; \
+ }
+
+#define INIT_ELMSIZE( lp, i, es ) \
+ { \
+ es = ((lp)->args[i]).elmsz; \
+ }
+
+#define INIT_PTR_BIT( lp, i, ad, ps, st ) \
+ { \
+ ps = ((lp)->args[i].iter[0]).pos; \
+ ad = (BIT_DIGIT*)(((lp)->args[i]).ptr) + ps/NB; \
+ ps %= NB; \
+ st = ((lp)->args[i].iter[0]).step; \
+ }
+
+#define INIT_PTR_BIT_IDX( lp, i, ad, ps, st, id ) \
+ { \
+ ps = ((lp)->args[i].iter[0]).pos; \
+ ad = (BIT_DIGIT*)(((lp)->args[i]).ptr) + ps/NB; \
+ ps %= NB; \
+ st = ((lp)->args[i].iter[0]).step; \
+ id = ((lp)->args[i].iter[0]).idx; \
+ }
+
+#define GET_DATA( ptr, type, val ) \
+ { \
+ val = *(type*)(ptr); \
+ }
+
+#define SET_DATA( ptr, type, val ) \
+ { \
+ *(type*)(ptr) = val; \
+ }
+
+#define GET_DATA_STRIDE( ptr, step, type, val ) \
+ { \
+ val = *(type*)(ptr); \
+ ptr += step; \
+ }
+
+#define GET_DATA_INDEX( ptr, idx, type, val ) \
+ { \
+ val = *(type*)(ptr + *idx); \
+ idx++; \
+ }
+
+#define SET_DATA_STRIDE( ptr, step, type, val ) \
+ { \
+ *(type*)(ptr) = val; \
+ ptr += step; \
+ }
+
+#define SET_DATA_INDEX( ptr, idx, type, val ) \
+ { \
+ *(type*)(ptr + *idx) = val; \
+ idx++; \
+ }
+
+#define LOAD_BIT( adr, pos, val ) \
+ { \
+ size_t dig = (pos) / NB; \
+ int bit = (pos) % NB; \
+ val = (((BIT_DIGIT*)(adr))[dig]>>(bit)) & 1u; \
+ }
+
+#define LOAD_BIT_STEP( adr, pos, step, idx, val ) \
+ { \
+ size_t dig; int bit; \
+ if (idx) { \
+ dig = ((pos) + *(idx)) / NB; \
+ bit = ((pos) + *(idx)) % NB; \
+ idx++; \
+ } else { \
+ dig = (pos) / NB; \
+ bit = (pos) % NB; \
+ pos += step; \
+ } \
+ val = (((BIT_DIGIT*)(adr))[dig]>>bit) & 1u; \
+ }
+
+#define STORE_BIT(adr,pos,val) \
+ { \
+ size_t dig = (pos) / NB; \
+ int bit = (pos) % NB; \
+ ((BIT_DIGIT*)(adr))[dig] = \
+ (((BIT_DIGIT*)(adr))[dig] & ~(1u<<(bit))) | ((val)<<(bit)); \
+ }
+// val -> val&1 ??
+
+#define STORE_BIT_STEP( adr, pos, step, idx, val )\
+ { \
+ size_t dig; int bit; \
+ if (idx) { \
+ dig = ((pos) + *(idx)) / NB; \
+ bit = ((pos) + *(idx)) % NB; \
+ idx++; \
+ } else { \
+ dig = (pos) / NB; \
+ bit = (pos) % NB; \
+ pos += step; \
+ } \
+ ((BIT_DIGIT*)(adr))[dig] = \
+ (((BIT_DIGIT*)(adr))[dig] & ~(1u<<(bit))) | ((val)<<(bit)); \
+ }
+// val -> val&1 ??
+
+#endif /* ifndef NARRAY_H */
diff --git a/ext/numo/narray/numo/types/bit.h b/ext/numo/narray/numo/types/bit.h
new file mode 100644
index 0000000..1cf3e94
--- /dev/null
+++ b/ext/numo/narray/numo/types/bit.h
@@ -0,0 +1,33 @@
+typedef BIT_DIGIT dtype;
+typedef BIT_DIGIT rtype;
+#define cT numo_cBit
+#define cRT cT
+
+#define m_zero 0
+#define m_one 1
+
+#define m_abs(x) (x)
+#define m_sign(x) (((x)==0) ? 0:1)
+
+#define m_from_double(x) (((x)==0) ? 0 : 1)
+#define m_from_real(x) (((x)==0) ? 0 : 1)
+#define m_data_to_num(x) INT2FIX(x)
+#define m_sprintf(s,x) sprintf(s,"%1d",(int)(x))
+
+#define m_copy(x) (x)
+#define m_not(x) (~(x))
+#define m_and(x,y) ((x)&(y))
+#define m_or(x,y) ((x)|(y))
+#define m_xor(x,y) ((x)^(y))
+#define m_eq(x,y) (~((x)^(y)))
+#define m_count_true(x) ((x)!=0)
+#define m_count_false(x) ((x)==0)
+
+static inline BIT_DIGIT m_num_to_data(VALUE num) {
+ if (RTEST(num)) {
+ if (!RTEST(rb_equal(num,INT2FIX(0)))) {
+ return 1;
+ }
+ }
+ return 0;
+}
diff --git a/ext/numo/narray/numo/types/complex.h b/ext/numo/narray/numo/types/complex.h
new file mode 100644
index 0000000..9e476fe
--- /dev/null
+++ b/ext/numo/narray/numo/types/complex.h
@@ -0,0 +1,409 @@
+/*
+ complex.h
+ Numerical Array Extension for Ruby
+ (C) Copyright 1999-2017 by Masahiro TANAKA
+*/
+
+
+static inline dtype c_new(rtype r, rtype i) {
+ dtype z;
+ REAL(z) = r;
+ IMAG(z) = i;
+ return z;
+}
+
+static inline dtype c_set_real(dtype x, rtype r) {
+ REAL(x)=r;
+ return x;
+}
+
+static inline dtype c_set_imag(dtype x, rtype i) {
+ IMAG(x)=i;
+ return x;
+}
+
+static inline VALUE COMP2NUM(dtype x) {
+ VALUE v;
+ v = rb_funcall(rb_intern("Kernel"), rb_intern("Complex"), 2,
+ rb_float_new(REAL(x)), rb_float_new(IMAG(x)));
+ return v;
+}
+
+static inline dtype NUM2COMP(VALUE v) {
+ dtype z;
+ REAL(z) = NUM2DBL(rb_funcall(v,id_real,0));
+ IMAG(z) = NUM2DBL(rb_funcall(v,id_imag,0));
+ return z;
+}
+
+#define c_is_zero(x) (REAL(x)==0 && IMAG(x)==0)
+#define c_eq(x,y) (REAL(x)==REAL(y) && IMAG(x)==IMAG(y))
+#define c_ne(x,y) (REAL(x)!=REAL(y) || IMAG(x)!=IMAG(y))
+#define c_isnan(x) (isnan(REAL(x)) || isnan(IMAG(x)))
+#define c_isinf(x) (isinf(REAL(x)) || isinf(IMAG(x)))
+#define c_isposinf(x) ((isinf(REAL(x)) && signbit(REAL(x))==0) || \
+ (isinf(IMAG(x)) && signbit(IMAG(x))==0))
+#define c_isneginf(x) ((isinf(REAL(x)) && signbit(REAL(x))) || \
+ (isinf(IMAG(x)) && signbit(IMAG(x))))
+#define c_isfinite(x) (isfinite(REAL(x)) && isfinite(IMAG(x)))
+
+static inline dtype c_zero() {
+ dtype z;
+ REAL(z) = 0;
+ IMAG(z) = 0;
+ return z;
+}
+
+static inline dtype c_one() {
+ dtype z;
+ REAL(z) = 1;
+ IMAG(z) = 0;
+ return z;
+}
+
+static inline dtype c_minus(dtype x) {
+ dtype z;
+ REAL(z) = -REAL(x);
+ IMAG(z) = -IMAG(x);
+ return z;
+}
+
+static inline dtype c_im(dtype x) {
+ dtype z;
+ REAL(z) = -IMAG(x);
+ IMAG(z) = REAL(x);
+ return z;
+}
+
+static inline dtype c_add(dtype x, dtype y) {
+ dtype z;
+ REAL(z) = REAL(x)+REAL(y);
+ IMAG(z) = IMAG(x)+IMAG(y);
+ return z;
+}
+
+static inline dtype c_sub(dtype x, dtype y) {
+ dtype z;
+ REAL(z) = REAL(x)-REAL(y);
+ IMAG(z) = IMAG(x)-IMAG(y);
+ return z;
+}
+
+
+static inline dtype c_mul(dtype x, dtype y) {
+ dtype z;
+ REAL(z) = REAL(x)*REAL(y)-IMAG(x)*IMAG(y);
+ IMAG(z) = REAL(x)*IMAG(y)+IMAG(x)*REAL(y);
+ return z;
+}
+
+static inline dtype c_mul_r(dtype x, rtype y) {
+ dtype z;
+ REAL(z) = REAL(x)*y;
+ IMAG(z) = IMAG(x)*y;
+ return z;
+}
+
+static inline dtype c_div(dtype x, dtype y) {
+ dtype z;
+ rtype s,yr,yi;
+ s = r_hypot(REAL(y),IMAG(y));
+ yr = REAL(y)/s;
+ yi = IMAG(y)/s;
+ REAL(z) = (REAL(x)*yr+IMAG(x)*yi)/s;
+ IMAG(z) = (IMAG(x)*yr-REAL(x)*yi)/s;
+ return z;
+}
+
+static inline dtype c_div_r(dtype x, rtype y) {
+ dtype z;
+ REAL(z) = REAL(x)/y;
+ IMAG(z) = IMAG(x)/y;
+ return z;
+}
+
+static inline dtype c_reciprocal(dtype x) {
+ dtype z;
+ if ( r_abs(REAL(x)) > r_abs(IMAG(x)) ) {
+ IMAG(z) = IMAG(x)/REAL(x);
+ REAL(z) = (1+IMAG(z)*IMAG(z))*REAL(x);
+ IMAG(z) /= -REAL(z);
+ REAL(z) = 1/REAL(z);
+ } else {
+ REAL(z) = REAL(x)/IMAG(x);
+ IMAG(z) = (1+REAL(z)*REAL(z))*IMAG(x);
+ REAL(z) /= IMAG(z);
+ IMAG(z) = -1/IMAG(z);
+ }
+ return z;
+}
+
+static inline dtype c_square(dtype x) {
+ dtype z;
+ REAL(z) = REAL(x)*REAL(x)-IMAG(x)*IMAG(x);
+ IMAG(z) = 2*REAL(x)*IMAG(x);
+ return z;
+}
+
+static inline dtype c_sqrt(dtype x) {
+ dtype z;
+ rtype xr, xi, r;
+ xr = REAL(x)/2;
+ xi = IMAG(x)/2;
+ r = r_hypot(xr,xi);
+ if (xr>0) {
+ REAL(z) = sqrt(r+xr);
+ IMAG(z) = xi/REAL(z);
+ } else if ( (r-=xr)!=0 ) {
+ IMAG(z) = (xi>=0) ? sqrt(r):-sqrt(r);
+ REAL(z) = xi/IMAG(z);
+ } else {
+ REAL(z) = IMAG(z) = 0;
+ }
+ return z;
+}
+
+static inline dtype c_log(dtype x) {
+ dtype z;
+ REAL(z) = r_log(r_hypot(REAL(x),IMAG(x)));
+ IMAG(z) = r_atan2(IMAG(x),REAL(x));
+ return z;
+}
+
+static inline dtype c_log2(dtype x) {
+ dtype z;
+ z = c_log(x);
+ z = c_mul_r(x,M_LOG2E);
+ return z;
+}
+
+static inline dtype c_log10(dtype x) {
+ dtype z;
+ z = c_log(x);
+ z = c_mul_r(x,M_LOG10E);
+ return z;
+}
+
+static inline dtype c_exp(dtype x) {
+ dtype z;
+ rtype a = r_exp(REAL(x));
+ REAL(z) = a*r_cos(IMAG(x));
+ IMAG(z) = a*r_sin(IMAG(x));
+ return z;
+}
+
+static inline dtype c_exp2(dtype x) {
+ dtype z;
+ rtype a = r_exp(REAL(x)*M_LN2);
+ REAL(z) = a*r_cos(IMAG(x));
+ IMAG(z) = a*r_sin(IMAG(x));
+ return z;
+}
+
+static inline dtype c_exp10(dtype x) {
+ dtype z;
+ rtype a = r_exp(REAL(x)*M_LN10);
+ REAL(z) = a*r_cos(IMAG(x));
+ IMAG(z) = a*r_sin(IMAG(x));
+ return z;
+}
+
+static inline dtype c_sin(dtype x) {
+ dtype z;
+ REAL(z) = r_sin(REAL(x))*r_cosh(IMAG(x));
+ IMAG(z) = r_cos(REAL(x))*r_sinh(IMAG(x));
+ return z;
+}
+
+static inline dtype c_sinh(dtype x) {
+ dtype z;
+ REAL(z) = r_sinh(REAL(x))*r_cos(IMAG(x));
+ IMAG(z) = r_cosh(REAL(x))*r_sin(IMAG(x));
+ return z;
+}
+
+static inline dtype c_cos(dtype x) {
+ dtype z;
+ REAL(z) = r_cos(REAL(x))*r_cosh(IMAG(x));
+ IMAG(z) = -r_sin(REAL(x))*r_sinh(IMAG(x));
+ return z;
+}
+
+static inline dtype c_cosh(dtype x) {
+ dtype z;
+ REAL(z) = r_cosh(REAL(x))*r_cos(IMAG(x));
+ IMAG(z) = r_sinh(REAL(x))*r_sin(IMAG(x));
+ return z;
+}
+
+static inline dtype c_tan(dtype x) {
+ dtype z;
+ rtype c, d;
+ if (r_abs(IMAG(x))<1) {
+ c = r_cos(REAL(x));
+ d = r_sinh(IMAG(x));
+ d = c*c + d*d;
+ REAL(z) = 0.5*r_sin(2*REAL(x))/d;
+ IMAG(z) = 0.5*r_sinh(2*IMAG(x))/d;
+ } else {
+ d = r_exp(-IMAG(x));
+ c = 2*d/(1-d*d);
+ c = c*c;
+ d = r_cos(REAL(x));
+ d = 1.0 + d*d*c;
+ REAL(z) = 0.5*r_sin(2*REAL(x))*c/d;
+ IMAG(z) = 1/r_tanh(IMAG(x))/d;
+ }
+ return z;
+}
+
+static inline dtype c_tanh(dtype x) {
+ dtype z;
+ rtype c, d, s;
+ c = r_cos(IMAG(x));
+ s = r_sinh(REAL(x));
+ d = c*c + s*s;
+ if (r_abs(REAL(x))<1) {
+ REAL(z) = s*r_cosh(REAL(x))/d;
+ IMAG(z) = 0.5*r_sin(2*IMAG(x))/d;
+ } else {
+ c = c / s;
+ c = 1 + c*c;
+ REAL(z) = 1/(r_tanh(REAL(x))*c);
+ IMAG(z) = 0.5*r_sin(2*IMAG(x))/d;
+ }
+ return z;
+}
+
+static inline dtype c_asin(dtype x) {
+ dtype z, y;
+ y = c_square(x);
+ REAL(y) = 1-REAL(y);
+ IMAG(y) = -IMAG(y);
+ y = c_sqrt(y);
+ REAL(y) -= IMAG(x);
+ IMAG(y) += REAL(x);
+ y = c_log(y);
+ REAL(z) = IMAG(y);
+ IMAG(z) = -REAL(y);
+ return z;
+}
+
+static inline dtype c_asinh(dtype x) {
+ dtype z, y;
+ y = c_square(x);
+ REAL(y) += 1;
+ y = c_sqrt(y);
+ REAL(y) += REAL(x);
+ IMAG(y) += IMAG(x);
+ z = c_log(y);
+ return z;
+}
+
+static inline dtype c_acos(dtype x) {
+ dtype z, y;
+ y = c_square(x);
+ REAL(y) = 1-REAL(y);
+ IMAG(y) = -IMAG(y);
+ y = c_sqrt(y);
+ REAL(z) = REAL(x)-IMAG(y);
+ IMAG(z) = IMAG(x)+REAL(y);
+ y = c_log(z);
+ REAL(z) = IMAG(y);
+ IMAG(z) = -REAL(y);
+ return z;
+}
+
+static inline dtype c_acosh(dtype x) {
+ dtype z, y;
+ y = c_square(x);
+ REAL(y) -= 1;
+ y = c_sqrt(y);
+ REAL(y) += REAL(x);
+ IMAG(y) += IMAG(x);
+ z = c_log(y);
+ return z;
+}
+
+static inline dtype c_atan(dtype x) {
+ dtype z, y;
+ REAL(y) = -REAL(x);
+ IMAG(y) = 1-IMAG(x);
+ REAL(z) = REAL(x);
+ IMAG(z) = 1+IMAG(x);
+ y = c_div(z,y);
+ y = c_log(y);
+ REAL(z) = -IMAG(y)/2;
+ IMAG(z) = REAL(y)/2;
+ return z;
+}
+
+static inline dtype c_atanh(dtype x) {
+ dtype z, y;
+ REAL(y) = 1-REAL(x);
+ IMAG(y) = -IMAG(x);
+ REAL(z) = 1+REAL(x);
+ IMAG(z) = IMAG(x);
+ y = c_div(z,y);
+ y = c_log(y);
+ REAL(z) = REAL(y)/2;
+ IMAG(z) = IMAG(y)/2;
+ return z;
+}
+
+static inline dtype c_pow(dtype x, dtype y)
+{
+ dtype z;
+ if (c_is_zero(y)) {
+ z = c_one();
+ } else if (c_is_zero(x) && REAL(y)>0 && IMAG(y)==0) {
+ z = c_zero();
+ } else {
+ z = c_log(x);
+ z = c_mul(y,z);
+ z = c_exp(z);
+ }
+ return z;
+}
+
+static inline dtype c_pow_int(dtype x, int p)
+{
+ dtype z = c_one();
+ if (p<0) {
+ x = c_pow_int(x,-p);
+ return c_reciprocal(x);
+ }
+ if (p==2) {return c_square(x);}
+ if (p&1) {z = x;}
+ p >>= 1;
+ while (p) {
+ x = c_square(x);
+ if (p&1) z = c_mul(z,x);
+ p >>= 1;
+ }
+ return z;
+}
+
+static inline dtype c_cbrt(dtype x) {
+ dtype z;
+ z = c_log(x);
+ z = c_div_r(z,3);
+ z = c_exp(z);
+ return z;
+}
+
+static inline rtype c_abs(dtype x) {
+ return r_hypot(REAL(x),IMAG(x));
+}
+
+static inline rtype c_abs_square(dtype x) {
+ return REAL(x)*REAL(x)+IMAG(x)*IMAG(x);
+}
+
+
+
+/*
+static inline rtype c_hypot(dtype x, dtype y) {
+ return r_hypot(c_abs(x),c_abs(y));
+}
+*/
diff --git a/ext/numo/narray/numo/types/complex_macro.h b/ext/numo/narray/numo/types/complex_macro.h
new file mode 100644
index 0000000..7adadbb
--- /dev/null
+++ b/ext/numo/narray/numo/types/complex_macro.h
@@ -0,0 +1,375 @@
+#include "float_def.h"
+
+EXTERN double round(double);
+EXTERN double log2(double);
+EXTERN double exp2(double);
+EXTERN double exp10(double);
+
+#define r_abs(x) fabs(x)
+#define r_sqrt(x) sqrt(x)
+#define r_exp(x) exp(x)
+#define r_log(x) log(x)
+#define r_sin(x) sin(x)
+#define r_cos(x) cos(x)
+#define r_sinh(x) sinh(x)
+#define r_cosh(x) cosh(x)
+#define r_tanh(x) tanh(x)
+#define r_atan2(y,x) atan2(y,x)
+#define r_hypot(x,y) hypot(x,y)
+
+#include "complex.h"
+
+static inline dtype c_from_scomplex(scomplex x) {
+ dtype z;
+ REAL(z) = REAL(x);
+ IMAG(z) = IMAG(x);
+ return z;
+}
+
+static inline dtype c_from_dcomplex(dcomplex x) {
+ dtype z;
+ REAL(z) = REAL(x);
+ IMAG(z) = IMAG(x);
+ return z;
+}
+
+/* --------------------------- */
+
+#define m_zero c_zero()
+#define m_one c_one()
+
+#define m_num_to_data(x) NUM2COMP(x)
+#define m_data_to_num(x) COMP2NUM(x)
+
+#define m_from_double(x) c_new(x,0)
+#define m_from_real(x) c_new(x,0)
+#define m_from_scomplex(x) c_from_scomplex(x)
+#define m_from_dcomplex(x) c_from_dcomplex(x)
+
+#define m_extract(x) COMP2NUM(*(dtype*)x)
+
+#define m_real(x) REAL(x)
+#define m_imag(x) IMAG(x)
+#define m_set_real(x,y) c_set_real(x,y)
+#define m_set_imag(x,y) c_set_imag(x,y)
+
+#define m_add(x,y) c_add(x,y)
+#define m_sub(x,y) c_sub(x,y)
+#define m_mul(x,y) c_mul(x,y)
+#define m_div(x,y) c_div(x,y)
+#define m_mod(x,y) c_mod(x,y)
+#define m_pow(x,y) c_pow(x,y)
+#define m_pow_int(x,y) c_pow_int(x,y)
+
+#define m_abs(x) c_abs(x)
+#define m_minus(x) c_minus(x)
+#define m_reciprocal(x) c_reciprocal(x)
+#define m_square(x) c_square(x)
+#define m_floor(x) c_new(floor(REAL(x)),floor(IMAG(x)))
+#define m_round(x) c_new(round(REAL(x)),round(IMAG(x)))
+#define m_ceil(x) c_new(ceil(REAL(x)),ceil(IMAG(x)))
+#define m_trunc(x) c_new(trunc(REAL(x)),trunc(IMAG(x)))
+#define m_rint(x) c_new(rint(REAL(x)),rint(IMAG(x)))
+#define m_sign(x) c_new( \
+ ((REAL(x)==0) ? 0.0:((REAL(x)>0) ? 1.0:((REAL(x)<0) ? -1.0:REAL(x)))), \
+ ((IMAG(x)==0) ? 0.0:((IMAG(x)>0) ? 1.0:((IMAG(x)<0) ? -1.0:IMAG(x)))))
+#define m_copysign(x,y) c_new(copysign(REAL(x),REAL(y)),copysign(IMAG(x),IMAG(y)))
+
+#define m_im(x) c_im(x)
+#define m_conj(x) c_new(REAL(x),-IMAG(x))
+#define m_arg(x) atan2(IMAG(x),REAL(x))
+
+#define m_eq(x,y) c_eq(x,y)
+#define m_ne(x,y) c_ne(x,y)
+#define m_nearly_eq(x,y) c_nearly_eq(x,y)
+
+#define m_isnan(x) c_isnan(x)
+#define m_isinf(x) c_isinf(x)
+#define m_isposinf(x) c_isposinf(x)
+#define m_isneginf(x) c_isneginf(x)
+#define m_isfinite(x) c_isfinite(x)
+
+#define m_sprintf(s,x) sprintf(s,"%g%+gi",REAL(x),IMAG(x))
+
+#define m_sqrt(x) c_sqrt(x)
+#define m_cbrt(x) c_cbrt(x)
+#define m_log(x) c_log(x)
+#define m_log2(x) c_log2(x)
+#define m_log10(x) c_log10(x)
+#define m_exp(x) c_exp(x)
+#define m_exp2(x) c_exp2(x)
+#define m_exp10(x) c_exp10(x)
+#define m_sin(x) c_sin(x)
+#define m_cos(x) c_cos(x)
+#define m_tan(x) c_tan(x)
+#define m_asin(x) c_asin(x)
+#define m_acos(x) c_acos(x)
+#define m_atan(x) c_atan(x)
+#define m_sinh(x) c_sinh(x)
+#define m_cosh(x) c_cosh(x)
+#define m_tanh(x) c_tanh(x)
+#define m_asinh(x) c_asinh(x)
+#define m_acosh(x) c_acosh(x)
+#define m_atanh(x) c_atanh(x)
+#define m_hypot(x,y) c_hypot(x,y)
+#define m_sinc(x) c_div(c_sin(x),x)
+
+#define m_sum_init INT2FIX(0)
+#define m_mulsum_init INT2FIX(0)
+
+#define m_mulsum(x,y,z) {z = m_add(m_mul(x,y),z);}
+#define m_mulsum_nan(x,y,z) { \
+ if(!m_isnan(x) && !m_isnan(y)) { \
+ z = m_add(m_mul(x,y),z); \
+ }}
+
+#define m_cumsum(x,y) {(x)=m_add(x,y);}
+#define m_cumsum_nan(x,y) { \
+ if (m_isnan(x)) { \
+ (x) = (y); \
+ } else if (!m_isnan(y)) { \
+ (x) = m_add(x,y); \
+ }}
+
+#define m_cumprod(x,y) {(x)=m_mul(x,y);}
+#define m_cumprod_nan(x,y) { \
+ if (m_isnan(x)) { \
+ (x) = (y); \
+ } else if (!m_isnan(y)) { \
+ (x) = m_mul(x,y); \
+ }}
+
+static inline dtype f_sum(size_t n, char *p, ssize_t stride)
+{
+ size_t i=n;
+ dtype x,y;
+
+ y = c_zero();
+ for (; i--;) {
+ x = *(dtype*)p;
+ y = c_add(x,y);
+ p += stride;
+ }
+ return y;
+}
+
+static inline dtype f_sum_nan(size_t n, char *p, ssize_t stride)
+{
+ size_t i=n;
+ dtype x,y;
+
+ y = c_zero();
+ for (; i--;) {
+ x = *(dtype*)p;
+ if (!c_isnan(x)) {
+ y = c_add(x,y);
+ }
+ p += stride;
+ }
+ return y;
+}
+
+static inline dtype f_kahan_sum(size_t n, char *p, ssize_t stride)
+{
+ size_t i=n;
+ dtype x;
+ volatile dtype y,t,r;
+
+ y = c_zero();
+ r = c_zero();
+ for (; i--;) {
+ x = *(dtype*)p;
+ if (fabs(REAL(x)) > fabs(REAL(y))) {
+ double z=REAL(x); REAL(x)=REAL(y); REAL(y)=z;
+ }
+ if (fabs(IMAG(x)) > fabs(IMAG(y))) {
+ double z=IMAG(x); IMAG(x)=IMAG(y); IMAG(y)=z;
+ }
+ r = c_add(x, r);
+ t = y;
+ y = c_add(r, y);
+ t = c_sub(y, t);
+ r = c_sub(r, t);
+ p += stride;
+ }
+ return y;
+}
+
+static inline dtype f_kahan_sum_nan(size_t n, char *p, ssize_t stride)
+{
+ size_t i=n;
+ dtype x;
+ volatile dtype y,t,r;
+
+ y = c_zero();
+ r = c_zero();
+ for (; i--;) {
+ x = *(dtype*)p;
+ if (!c_isnan(x)) {
+ if (fabs(REAL(x)) > fabs(REAL(y))) {
+ double z=REAL(x); REAL(x)=REAL(y); REAL(y)=z;
+ }
+ if (fabs(IMAG(x)) > fabs(IMAG(y))) {
+ double z=IMAG(x); IMAG(x)=IMAG(y); IMAG(y)=z;
+ }
+ r = c_add(x, r);
+ t = y;
+ y = c_add(r, y);
+ t = c_sub(y, t);
+ r = c_sub(r, t);
+ }
+ p += stride;
+ }
+ return y;
+}
+
+static inline dtype f_prod(size_t n, char *p, ssize_t stride)
+{
+ size_t i=n;
+ dtype x,y;
+
+ y = c_one();
+ for (; i--;) {
+ x = *(dtype*)p;
+ y = c_mul(x,y);
+ p += stride;
+ }
+ return y;
+}
+
+static inline dtype f_prod_nan(size_t n, char *p, ssize_t stride)
+{
+ size_t i=n;
+ dtype x,y;
+
+ y = c_one();
+ for (; i--;) {
+ x = *(dtype*)p;
+ if (!c_isnan(x)) {
+ y = c_mul(x,y);
+ }
+ p += stride;
+ }
+ return y;
+}
+
+static inline dtype f_mean(size_t n, char *p, ssize_t stride)
+{
+ size_t i=n;
+ size_t count=0;
+ dtype x,y;
+
+ y = c_zero();
+ for (; i--;) {
+ x = *(dtype*)p;
+ y = c_add(x,y);
+ count++;
+ p += stride;
+ }
+ return c_div_r(y,count);
+}
+
+static inline dtype f_mean_nan(size_t n, char *p, ssize_t stride)
+{
+ size_t i=n;
+ size_t count=0;
+ dtype x,y;
+
+ y = c_zero();
+ for (; i--;) {
+ x = *(dtype*)p;
+ if (!c_isnan(x)) {
+ y = c_add(x,y);
+ count++;
+ }
+ p += stride;
+ }
+ return c_div_r(y,count);
+}
+
+static inline rtype f_var(size_t n, char *p, ssize_t stride)
+{
+ size_t i=n;
+ size_t count=0;
+ dtype x,m;
+ rtype y=0;
+
+ m = f_mean(n,p,stride);
+
+ for (; i--;) {
+ x = *(dtype*)p;
+ y += c_abs_square(c_sub(x,m));
+ count++;
+ p += stride;
+ }
+ return y/(count-1);
+}
+
+static inline rtype f_var_nan(size_t n, char *p, ssize_t stride)
+{
+ size_t i=n;
+ size_t count=0;
+ dtype x,m;
+ rtype y=0;
+
+ m = f_mean_nan(n,p,stride);
+
+ for (; i--;) {
+ x = *(dtype*)p;
+ if (!c_isnan(x)) {
+ y += c_abs_square(c_sub(x,m));
+ count++;
+ }
+ p += stride;
+ }
+ return y/(count-1);
+}
+
+static inline rtype f_stddev(size_t n, char *p, ssize_t stride)
+{
+ return r_sqrt(f_var(n,p,stride));
+}
+
+static inline rtype f_stddev_nan(size_t n, char *p, ssize_t stride)
+{
+ return r_sqrt(f_var_nan(n,p,stride));
+}
+
+static inline rtype f_rms(size_t n, char *p, ssize_t stride)
+{
+ size_t i=n;
+ size_t count=0;
+ dtype x;
+ rtype y=0;
+
+ for (; i--;) {
+ x = *(dtype*)p;
+ y += c_abs_square(x);
+ count++;
+ p += stride;
+ }
+ return r_sqrt(y/count);
+}
+
+static inline rtype f_rms_nan(size_t n, char *p, ssize_t stride)
+{
+ size_t i=n;
+ size_t count=0;
+ dtype x;
+ rtype y=0;
+
+ for (; i--;) {
+ x = *(dtype*)p;
+ if (!c_isnan(x)) {
+ y += c_abs_square(x);
+ count++;
+ }
+ p += stride;
+ }
+ return r_sqrt(y/count);
+}
+
+static inline dtype f_seq(dtype x, dtype y, double c)
+{
+ return c_add(x,c_mul_r(y,c));
+}
diff --git a/ext/numo/narray/numo/types/dcomplex.h b/ext/numo/narray/numo/types/dcomplex.h
new file mode 100644
index 0000000..3b3cb54
--- /dev/null
+++ b/ext/numo/narray/numo/types/dcomplex.h
@@ -0,0 +1,44 @@
+typedef dcomplex dtype;
+typedef double rtype;
+#define cT numo_cDComplex
+#define cRT numo_cDFloat
+#define mTM numo_mDComplexMath
+
+#include "complex_macro.h"
+
+static inline bool c_nearly_eq(dtype x, dtype y) {
+ return c_abs(c_sub(x,y)) <= (c_abs(x)+c_abs(y))*DBL_EPSILON*2;
+}
+
+#ifdef SFMT_H
+/* generates a random number on [0,1)-real-interval */
+inline static dtype m_rand(dtype max)
+{
+ dtype z;
+ REAL(z) = genrand_res53_mix() * REAL(max);
+ IMAG(z) = genrand_res53_mix() * IMAG(max);
+ return z;
+}
+
+/* generates random numbers from the normal distribution
+ using Box-Muller Transformation.
+ */
+inline static void m_rand_norm(dtype mu, rtype sigma, dtype *a0)
+{
+ rtype x1, x2, w;
+ do {
+ x1 = genrand_res53_mix();
+ x1 = x1*2-1;
+ x2 = genrand_res53_mix();
+ x2 = x2*2-1;
+ w = x1 * x1 + x2 * x2;
+ } while (w>=1);
+ w = sqrt( (-2*log(w)) / w );
+ REAL(*a0) = x1*w * sigma + REAL(mu);
+ IMAG(*a0) = x2*w * sigma + IMAG(mu);
+}
+#endif
+
+#define M_EPSILON rb_float_new(2.2204460492503131e-16)
+#define M_MIN rb_float_new(2.2250738585072014e-308)
+#define M_MAX rb_float_new(1.7976931348623157e+308)
diff --git a/ext/numo/narray/numo/types/dfloat.h b/ext/numo/narray/numo/types/dfloat.h
new file mode 100644
index 0000000..42e68a3
--- /dev/null
+++ b/ext/numo/narray/numo/types/dfloat.h
@@ -0,0 +1,42 @@
+typedef double dtype;
+typedef double rtype;
+#define cT numo_cDFloat
+#define cRT numo_cDFloat
+#define mTM numo_mDFloatMath
+
+#include "float_macro.h"
+
+#ifdef SFMT_H
+/* generates a random number on [0,1)-real-interval */
+inline static dtype m_rand(dtype max)
+{
+ return genrand_res53_mix() * max;
+}
+
+/* generates random numbers from the normal distribution
+ using Box-Muller Transformation.
+ */
+inline static void m_rand_norm(dtype mu, dtype sigma, dtype *a0, dtype *a1)
+{
+ dtype x1, x2, w;
+ do {
+ x1 = genrand_res53_mix();
+ x1 = x1*2-1;
+ x2 = genrand_res53_mix();
+ x2 = x2*2-1;
+ w = x1 * x1 + x2 * x2;
+ } while (w>=1);
+ w = sqrt( (-2*log(w)) / w );
+ if (a0) {*a0 = x1*w * sigma + mu;}
+ if (a1) {*a1 = x2*w * sigma + mu;}
+}
+#endif
+
+#define m_min_init numo_dfloat_new_dim0(0.0/0.0)
+#define m_max_init numo_dfloat_new_dim0(0.0/0.0)
+#define m_extract(x) rb_float_new(*(double*)x)
+#define m_nearly_eq(x,y) (fabs(x-y)<=(fabs(x)+fabs(y))*DBL_EPSILON*2)
+
+#define M_EPSILON rb_float_new(2.2204460492503131e-16)
+#define M_MIN rb_float_new(2.2250738585072014e-308)
+#define M_MAX rb_float_new(1.7976931348623157e+308)
diff --git a/ext/numo/narray/numo/types/float_def.h b/ext/numo/narray/numo/types/float_def.h
new file mode 100644
index 0000000..a9d22f1
--- /dev/null
+++ b/ext/numo/narray/numo/types/float_def.h
@@ -0,0 +1,34 @@
+#ifndef DBL_EPSILON
+#define DBL_EPSILON 2.2204460492503131e-16
+#endif
+#ifndef FLT_EPSILON
+#define FLT_EPSILON 1.1920928955078125e-07
+#endif
+#ifndef DBL_MAX
+#define DBL_MAX 1.7976931348623157e+308
+#endif
+#ifndef DBL_MAX
+#define DBL_MAX 1.7976931348623157e+308
+#endif
+#ifndef FLT_MIN
+#define FLT_MIN 1.1754943508222875e-38
+#endif
+#ifndef FLT_MAX
+#define FLT_MAX 3.4028234663852886e+38
+#endif
+
+#ifndef M_PI_2
+#define M_PI_2 1.57079632679489661923 /* pi/2 */
+#endif
+#ifndef M_LOG2E
+#define M_LOG2E 1.4426950408889634074 /* log_2 e */
+#endif
+#ifndef M_LOG10E
+#define M_LOG10E 0.43429448190325182765 /* log_10 e */
+#endif
+#ifndef M_LN2
+#define M_LN2 0.69314718055994530942 /* log_e 2 */
+#endif
+#ifndef M_LN10
+#define M_LN10 2.30258509299404568402 /* log_e 10 */
+#endif
diff --git a/ext/numo/narray/numo/types/float_macro.h b/ext/numo/narray/numo/types/float_macro.h
new file mode 100644
index 0000000..3b50e35
--- /dev/null
+++ b/ext/numo/narray/numo/types/float_macro.h
@@ -0,0 +1,186 @@
+#include "float_def.h"
+
+EXTERN double round(double);
+EXTERN double log2(double);
+EXTERN double exp2(double);
+#ifdef HAVE_EXP10
+EXTERN double exp10(double);
+#else
+EXTERN double pow(double, double);
+#endif
+
+#define m_zero 0.0
+#define m_one 1.0
+
+#define m_num_to_data(x) NUM2DBL(x)
+#define m_data_to_num(x) rb_float_new(x)
+
+#define m_from_double(x) (x)
+#define m_from_real(x) (x)
+
+#define m_add(x,y) ((x)+(y))
+#define m_sub(x,y) ((x)-(y))
+#define m_mul(x,y) ((x)*(y))
+#define m_div(x,y) ((x)/(y))
+#define m_div_check(x,y) ((y)==0)
+#define m_mod(x,y) fmod(x,y)
+#define m_divmod(x,y,a,b) {a=(x)/(y); b=m_mod(x,y);}
+#define m_pow(x,y) pow(x,y)
+#define m_pow_int(x,y) pow_int(x,y)
+
+#define m_abs(x) fabs(x)
+#define m_minus(x) (-(x))
+#define m_reciprocal(x) (1/(x))
+#define m_square(x) ((x)*(x))
+#define m_floor(x) floor(x)
+#define m_round(x) round(x)
+#define m_ceil(x) ceil(x)
+#define m_trunc(x) trunc(x)
+#define m_rint(x) rint(x)
+#define m_sign(x) (((x)==0) ? 0.0:(((x)>0) ? 1.0:(((x)<0) ? -1.0:(x))))
+#define m_copysign(x,y) copysign(x,y)
+#define m_signbit(x) signbit(x)
+#define m_modf(x,y,z) {double d; y=modf(x,&d); z=d;}
+
+#define m_eq(x,y) ((x)==(y))
+#define m_ne(x,y) ((x)!=(y))
+#define m_gt(x,y) ((x)>(y))
+#define m_ge(x,y) ((x)>=(y))
+#define m_lt(x,y) ((x)<(y))
+#define m_le(x,y) ((x)<=(y))
+
+#define m_isnan(x) isnan(x)
+#define m_isinf(x) isinf(x)
+#define m_isposinf(x) (isinf(x) && signbit(x)==0)
+#define m_isneginf(x) (isinf(x) && signbit(x))
+#define m_isfinite(x) isfinite(x)
+
+#define m_mulsum_init INT2FIX(0)
+
+#define m_sprintf(s,x) sprintf(s,"%g",x)
+
+#define cmp_prnan(a,b) \
+ ((qsort_cast(a)==qsort_cast(b)) ? 0 : \
+ (qsort_cast(a) > qsort_cast(b)) ? 1 : -1)
+
+#define cmp_ignan(a,b) \
+ (m_isnan(qsort_cast(a)) ? (m_isnan(qsort_cast(b)) ? 0 : 1) : \
+ (m_isnan(qsort_cast(b)) ? -1 : \
+ ((qsort_cast(a)==qsort_cast(b)) ? 0 : \
+ (qsort_cast(a) > qsort_cast(b)) ? 1 : -1)))
+
+#define cmpgt_prnan(a,b) \
+ (qsort_cast(a) > qsort_cast(b))
+
+#define cmpgt_ignan(a,b) \
+ ((m_isnan(qsort_cast(a)) && !m_isnan(qsort_cast(b))) || \
+ (qsort_cast(a) > qsort_cast(b)))
+
+#define m_sqrt(x) sqrt(x)
+#define m_cbrt(x) cbrt(x)
+#define m_log(x) log(x)
+#define m_log2(x) log2(x)
+#define m_log10(x) log10(x)
+#define m_exp(x) exp(x)
+#define m_exp2(x) exp2(x)
+#ifdef HAVE_EXP10
+#define m_exp10(x) exp10(x)
+#else
+#define m_exp10(x) pow(10, x)
+#endif
+#define m_expm1(x) expm1(x)
+#define m_log1p(x) log1p(x)
+
+#define m_sin(x) sin(x)
+#define m_cos(x) cos(x)
+#define m_tan(x) tan(x)
+#define m_asin(x) asin(x)
+#define m_acos(x) acos(x)
+#define m_atan(x) atan(x)
+#define m_sinh(x) sinh(x)
+#define m_cosh(x) cosh(x)
+#define m_tanh(x) tanh(x)
+#define m_asinh(x) asinh(x)
+#define m_acosh(x) acosh(x)
+#define m_atanh(x) atanh(x)
+#define m_atan2(x,y) atan2(x,y)
+#define m_hypot(x,y) hypot(x,y)
+#define m_sinc(x) (sin(x)/(x))
+
+#define m_erf(x) erf(x)
+#define m_erfc(x) erfc(x)
+#define m_ldexp(x,y) ldexp(x,y)
+#define m_frexp(x,exp) frexp(x,exp)
+
+static inline dtype pow_int(dtype x, int p)
+{
+ dtype r=1;
+ switch(p) {
+ case 0: return 1;
+ case 1: return x;
+ case 2: return x*x;
+ case 3: return x*x*x;
+ case 4: x=x*x; return x*x;
+ }
+ if (p<0) return 1/pow_int(x,-p);
+ if (p>64) return pow(x,p);
+ while (p) {
+ if (p&1) r *= x;
+ x *= x;
+ p >>= 1;
+ }
+ return r;
+}
+
+static inline dtype f_seq(dtype x, dtype y, double c)
+{
+ return x + y * c;
+}
+
+static inline dtype f_kahan_sum(size_t n, char *p, ssize_t stride)
+{
+ size_t i=n;
+ dtype x;
+ volatile dtype y=0;
+ volatile dtype t,r=0;
+
+ for (; i--;) {
+ x = *(dtype*)p;
+ p += stride;
+ if (fabs(x) > fabs(y)) {
+ dtype z=x; x=y; y=z;
+ }
+ r += x;
+ t = y;
+ y += r;
+ t = y-t;
+ r -= t;
+ }
+ return y;
+}
+
+static inline dtype f_kahan_sum_nan(size_t n, char *p, ssize_t stride)
+{
+ size_t i=n;
+ dtype x;
+ volatile dtype y=0;
+ volatile dtype t,r=0;
+
+ for (; i--;) {
+ x = *(dtype*)p;
+ p += stride;
+ if (!m_isnan(x)) {
+ if (fabs(x) > fabs(y)) {
+ dtype z=x; x=y; y=z;
+ }
+ r += x;
+ t = y;
+ y += r;
+ t = y-t;
+ r -= t;
+ }
+ }
+ return y;
+}
+
+#include "real_accum.h"
diff --git a/ext/numo/narray/numo/types/int16.h b/ext/numo/narray/numo/types/int16.h
new file mode 100644
index 0000000..9342f6a
--- /dev/null
+++ b/ext/numo/narray/numo/types/int16.h
@@ -0,0 +1,21 @@
+typedef int16_t dtype;
+typedef int16_t rtype;
+#define cT numo_cInt16
+#define cRT cT
+
+#define m_num_to_data(x) ((dtype)NUM2INT(x))
+#define m_data_to_num(x) INT2NUM((int)(x))
+#define m_extract(x) INT2NUM((int)*(dtype*)(x))
+#define m_sprintf(s,x) sprintf(s,"%d",(int)(x))
+
+#include "int_macro.h"
+
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+
+#define M_MIN m_data_to_num(INT16_MIN)
+#define M_MAX m_data_to_num(INT16_MAX)
diff --git a/ext/numo/narray/numo/types/int32.h b/ext/numo/narray/numo/types/int32.h
new file mode 100644
index 0000000..5d472d2
--- /dev/null
+++ b/ext/numo/narray/numo/types/int32.h
@@ -0,0 +1,21 @@
+typedef int32_t dtype;
+typedef int32_t rtype;
+#define cT numo_cInt32
+#define cRT cT
+
+#define m_num_to_data(x) ((dtype)NUM2INT32(x))
+#define m_data_to_num(x) INT322NUM((int32_t)(x))
+#define m_extract(x) INT322NUM((int32_t)*(dtype*)(x))
+#define m_sprintf(s,x) sprintf(s,"%"PRId32,(int32_t)(x))
+
+#include "int_macro.h"
+
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+
+#define M_MIN m_data_to_num(INT32_MIN)
+#define M_MAX m_data_to_num(INT32_MAX)
diff --git a/ext/numo/narray/numo/types/int64.h b/ext/numo/narray/numo/types/int64.h
new file mode 100644
index 0000000..bfb9426
--- /dev/null
+++ b/ext/numo/narray/numo/types/int64.h
@@ -0,0 +1,21 @@
+typedef int64_t dtype;
+typedef int64_t rtype;
+#define cT numo_cInt64
+#define cRT cT
+
+#define m_num_to_data(x) ((dtype)NUM2INT64(x))
+#define m_data_to_num(x) INT642NUM((int64_t)(x))
+#define m_extract(x) INT642NUM((int64_t)*(dtype*)(x))
+#define m_sprintf(s,x) sprintf(s,"%"PRId64,(int64_t)(x))
+
+#include "int_macro.h"
+
+#ifndef INT64_MIN
+#define INT64_MIN (-9223372036854775807l-1)
+#endif
+#ifndef INT64_MAX
+#define INT64_MAX (9223372036854775807l)
+#endif
+
+#define M_MIN m_data_to_num(INT64_MIN)
+#define M_MAX m_data_to_num(INT64_MAX)
diff --git a/ext/numo/narray/numo/types/int8.h b/ext/numo/narray/numo/types/int8.h
new file mode 100644
index 0000000..676d5e9
--- /dev/null
+++ b/ext/numo/narray/numo/types/int8.h
@@ -0,0 +1,21 @@
+typedef int8_t dtype;
+typedef int8_t rtype;
+#define cT numo_cInt8
+#define cRT cT
+
+#define m_num_to_data(x) ((dtype)NUM2INT(x))
+#define m_data_to_num(x) INT2NUM((int)(x))
+#define m_extract(x) INT2NUM((int)*(dtype*)(x))
+#define m_sprintf(s,x) sprintf(s,"%d",(int)(x))
+
+#include "int_macro.h"
+
+#ifndef INT8_MIN
+#define INT8_MIN (-127-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+
+#define M_MIN INT2FIX(INT8_MIN)
+#define M_MAX INT2FIX(INT8_MAX)
diff --git a/ext/numo/narray/numo/types/int_macro.h b/ext/numo/narray/numo/types/int_macro.h
new file mode 100644
index 0000000..d795426
--- /dev/null
+++ b/ext/numo/narray/numo/types/int_macro.h
@@ -0,0 +1,35 @@
+#include "xint_macro.h"
+
+#define m_abs(x) ((x<0)?-x:x)
+#define m_sign(x) (((x)==0) ? 0 : (((x)>0) ? 1 : -1))
+
+static inline dtype int_reciprocal(dtype x) {
+ switch (x) {
+ case 1:
+ return 1;
+ case -1:
+ return -1;
+ case 0:
+ rb_raise(rb_eZeroDivError, "divided by 0");
+ default:
+ return 0;
+ }
+}
+
+static dtype pow_int(dtype x, int p)
+{
+ dtype r = m_one;
+ switch(p) {
+ case 0: return 1;
+ case 1: return x;
+ case 2: return x*x;
+ case 3: return x*x*x;
+ }
+ if (p<0) return 0;
+ while (p) {
+ if (p&1) r *= x;
+ x *= x;
+ p >>= 1;
+ }
+ return r;
+}
diff --git a/ext/numo/narray/numo/types/real_accum.h b/ext/numo/narray/numo/types/real_accum.h
new file mode 100644
index 0000000..d0f68f6
--- /dev/null
+++ b/ext/numo/narray/numo/types/real_accum.h
@@ -0,0 +1,440 @@
+
+#define m_mulsum(x,y,z) {z = m_add(m_mul(x,y),z);}
+#define m_mulsum_nan(x,y,z) { \
+ if(!m_isnan(x) && !m_isnan(y)) { \
+ z = m_add(m_mul(x,y),z); \
+ }}
+
+#define m_cumsum(x,y) {(x)=m_add(x,y);}
+#define m_cumsum_nan(x,y) { \
+ if (m_isnan(x)) { \
+ (x) = (y); \
+ } else if (!m_isnan(y)) { \
+ (x) = m_add(x,y); \
+ }}
+
+#define m_cumprod(x,y) {(x)=m_mul(x,y);}
+#define m_cumprod_nan(x,y) { \
+ if (m_isnan(x)) { \
+ (x) = (y); \
+ } else if (!m_isnan(y)) { \
+ (x) = m_mul(x,y); \
+ }}
+
+static inline dtype f_sum(size_t n, char *p, ssize_t stride)
+{
+ size_t i=n;
+ dtype x,y=m_zero;
+
+ for (; i--;) {
+ x = *(dtype*)p;
+ p += stride;
+ y = m_add(x,y);
+ }
+ return y;
+}
+
+static inline dtype f_sum_nan(size_t n, char *p, ssize_t stride)
+{
+ size_t i=n;
+ dtype x,y=m_zero;
+
+ for (; i--;) {
+ x = *(dtype*)p;
+ p += stride;
+ if (!m_isnan(x)) {
+ y = m_add(x,y);
+ }
+ }
+ return y;
+}
+
+
+static inline dtype f_prod(size_t n, char *p, ssize_t stride)
+{
+ size_t i=n;
+ dtype x,y=m_one;
+
+ for (; i--;) {
+ x = *(dtype*)p;
+ p += stride;
+ y = m_mul(x,y);
+ }
+ return y;
+}
+
+static inline dtype f_prod_nan(size_t n, char *p, ssize_t stride)
+{
+ size_t i=n;
+ dtype x,y=m_one;
+
+ for (; i--;) {
+ x = *(dtype*)p;
+ p += stride;
+ if (!m_isnan(x)) {
+ y = m_mul(x,y);
+ }
+ }
+ return y;
+}
+
+static inline dtype f_mean(size_t n, char *p, ssize_t stride)
+{
+ size_t i=n;
+ size_t count=0;
+ dtype x,y=m_zero;
+
+ for (; i--;) {
+ x = *(dtype*)p;
+ p += stride;
+ y = m_add(x,y);
+ count++;
+ }
+ return m_div(y,m_from_real(count));
+}
+
+static inline dtype f_mean_nan(size_t n, char *p, ssize_t stride)
+{
+ size_t i=n;
+ size_t count=0;
+ dtype x,y=m_zero;
+
+ for (; i--;) {
+ x = *(dtype*)p;
+ p += stride;
+ if (!m_isnan(x)) {
+ y = m_add(x,y);
+ count++;
+ }
+ }
+ return m_div(y,m_from_real(count));
+}
+
+static inline dtype f_var(size_t n, char *p, ssize_t stride)
+{
+ size_t i=n;
+ size_t count=0;
+ dtype x,y=m_zero;
+ dtype a,m;
+
+ m = f_mean(n,p,stride);
+
+ for (; i--;) {
+ x = *(dtype*)p;
+ p += stride;
+ a = m_abs(m_sub(x,m));
+ y = m_add(y,m_square(a));
+ count++;
+ }
+ return m_div(y,m_from_real(count-1));
+}
+
+static inline dtype f_var_nan(size_t n, char *p, ssize_t stride)
+{
+ size_t i=n;
+ size_t count=0;
+ dtype x,y=m_zero;
+ dtype a,m;
+
+ m = f_mean_nan(n,p,stride);
+
+ for (; i--;) {
+ x = *(dtype*)p;
+ p += stride;
+ if (!m_isnan(x)) {
+ a = m_abs(m_sub(x,m));
+ y = m_add(y,m_square(a));
+ count++;
+ }
+ }
+ return m_div(y,m_from_real(count-1));
+}
+
+static inline dtype f_stddev(size_t n, char *p, ssize_t stride)
+{
+ return m_sqrt(f_var(n,p,stride));
+}
+
+static inline dtype f_stddev_nan(size_t n, char *p, ssize_t stride)
+{
+ return m_sqrt(f_var_nan(n,p,stride));
+}
+
+static inline dtype f_rms(size_t n, char *p, ssize_t stride)
+{
+ size_t i=n;
+ size_t count=0;
+ dtype x,y=m_zero;
+
+ for (; i--;) {
+ x = *(dtype*)p;
+ p += stride;
+ y = m_add(y,m_square(m_abs(x)));
+ count++;
+ }
+ return m_sqrt(m_div(y,m_from_real(count)));
+}
+
+static inline dtype f_rms_nan(size_t n, char *p, ssize_t stride)
+{
+ size_t i=n;
+ size_t count=0;
+ dtype x,y=m_zero;
+
+ for (; i--;) {
+ x = *(dtype*)p;
+ p += stride;
+ if (!m_isnan(x)) {
+ y = m_add(y,m_square(m_abs(x)));
+ count++;
+ }
+ }
+ return m_sqrt(m_div(y,m_from_real(count)));
+}
+
+// ---------------------------------------------------------
+
+static inline dtype f_min_nan(size_t n, char *p, ssize_t stride)
+{
+ dtype x,y;
+ size_t i=n;
+
+ y = *(dtype*)p;
+ p += stride;
+ if (m_isnan(y)) {return y;}
+ for (i--; i--;) {
+ x = *(dtype*)p;
+ p += stride;
+ if (m_isnan(x)) {return x;}
+ if (m_lt(x,y)) {
+ y = x;
+ }
+ }
+ return y;
+}
+
+static inline dtype f_min(size_t n, char *p, ssize_t stride)
+{
+ dtype x,y=m_zero;
+ size_t i=n;
+
+ for (; i--; ) {
+ y = *(dtype*)p;
+ p += stride;
+ if (!m_isnan(y)) {
+ for (; i--;) {
+ x = *(dtype*)p;
+ p += stride;
+ if (m_lt(x,y)) {
+ y = x;
+ }
+ }
+ break;
+ }
+ }
+ return y;
+}
+
+static inline dtype f_max_nan(size_t n, char *p, ssize_t stride)
+{
+ dtype x,y;
+ size_t i=n;
+
+ y = *(dtype*)p;
+ p += stride;
+ if (m_isnan(y)) {return y;}
+ for (i--; i--;) {
+ x = *(dtype*)p;
+ p += stride;
+ if (m_isnan(x)) {return x;}
+ if (m_gt(x,y)) {
+ y = x;
+ }
+ }
+ return y;
+}
+
+static inline dtype f_max(size_t n, char *p, ssize_t stride)
+{
+ dtype x,y=m_zero;
+ size_t i=n;
+
+ for (; i--; ) {
+ y = *(dtype*)p;
+ p += stride;
+ if (!m_isnan(y)) {
+ for (; i--;) {
+ x = *(dtype*)p;
+ p += stride;
+ if (m_gt(x,y)) {
+ y = x;
+ }
+ }
+ break;
+ }
+ }
+ return y;
+}
+
+static inline size_t f_min_index_nan(size_t n, char *p, ssize_t stride)
+{
+ dtype x, y;
+ size_t i, j=0;
+
+ y = *(dtype*)p;
+ p += stride;
+ if (m_isnan(y)) {return j;}
+ for (i=1; i<n; i++) {
+ x = *(dtype*)p;
+ p += stride;
+ if (m_isnan(x)) {return i;}
+ if (m_lt(x,y)) {
+ y = x;
+ j = i;
+ }
+ }
+ return j;
+}
+
+static inline size_t f_min_index(size_t n, char *p, ssize_t stride)
+{
+ dtype x, y;
+ size_t i, j=0;
+
+ for (i=0; i<n; i++) {
+ y = *(dtype*)p;
+ p += stride;
+ if (!m_isnan(y)) {
+ j = i;
+ for (; i<n; i++) {
+ x = *(dtype*)p;
+ p += stride;
+ if (m_lt(x,y)) {
+ y = x;
+ j = i;
+ }
+ }
+ break;
+ }
+ }
+ return j;
+}
+
+static inline size_t f_max_index_nan(size_t n, char *p, ssize_t stride)
+{
+ dtype x, y;
+ size_t i, j=0;
+
+ y = *(dtype*)p;
+ p += stride;
+ if (m_isnan(y)) {return j;}
+ for (i=1; i<n; i++) {
+ x = *(dtype*)p;
+ p += stride;
+ if (m_isnan(x)) {return i;}
+ if (m_gt(x,y)) {
+ y = x;
+ j = i;
+ }
+ }
+ return j;
+}
+
+static inline size_t f_max_index(size_t n, char *p, ssize_t stride)
+{
+ dtype x, y;
+ size_t i, j=0;
+
+ for (i=0; i<n; i++) {
+ y = *(dtype*)p;
+ p += stride;
+ if (!m_isnan(y)) {
+ j = i;
+ for (; i<n; i++) {
+ x = *(dtype*)p;
+ p += stride;
+ if (m_gt(x,y)) {
+ y = x;
+ j = i;
+ }
+ }
+ break;
+ }
+ }
+ return j;
+}
+
+static inline void
+f_minmax_nan(size_t n, char *p, ssize_t stride, dtype *amin, dtype *amax)
+{
+ dtype x,min,max;
+ size_t i=n;
+
+ min = max = *(dtype*)p;
+ p += stride;
+ if (m_isnan(min)) {
+ *amin = *amax = min;
+ return;
+ }
+ for (i--; i--;) {
+ x = *(dtype*)p;
+ p += stride;
+ if (m_isnan(x)) {
+ *amin = *amax = x;
+ return;
+ }
+ if (m_lt(x,min)) {
+ min = x;
+ }
+ if (m_gt(x,max)) {
+ max = x;
+ }
+ }
+ *amin = min;
+ *amax = max;
+ return;
+}
+
+static inline dtype f_ptp_nan(size_t n, char *p, ssize_t stride)
+{
+ dtype min,max;
+ f_minmax_nan(n,p,stride,&min,&max);
+ return m_sub(max,min);
+}
+
+static inline void
+f_minmax(size_t n, char *p, ssize_t stride, dtype *amin, dtype *amax)
+{
+ dtype x,min,max;
+ size_t i=n;
+
+ min = max = m_zero;
+ for (; i--; ) {
+ min = *(dtype*)p;
+ p += stride;
+ if (!m_isnan(min)) {
+ max = min;
+ for (; i--;) {
+ x = *(dtype*)p;
+ p += stride;
+ if (m_lt(x,min)) {
+ min = x;
+ }
+ if (m_gt(x,max)) {
+ max = x;
+ }
+ }
+ break;
+ }
+ }
+ *amin = min;
+ *amax = max;
+ return;
+}
+
+static inline dtype f_ptp(size_t n, char *p, ssize_t stride)
+{
+ dtype min,max;
+ f_minmax(n,p,stride,&min,&max);
+ return m_sub(max,min);
+}
diff --git a/ext/numo/narray/numo/types/robj_macro.h b/ext/numo/narray/numo/types/robj_macro.h
new file mode 100644
index 0000000..3ed73a7
--- /dev/null
+++ b/ext/numo/narray/numo/types/robj_macro.h
@@ -0,0 +1,75 @@
+#define m_zero INT2FIX(0)
+#define m_one INT2FIX(1)
+
+#define m_num_to_data(x) (x)
+#define m_data_to_num(x) (x)
+
+#define m_from_double(x) rb_float_new(x)
+#define m_from_real(x) rb_float_new(x)
+
+#define m_add(x,y) rb_funcall(x,'+',1,y)
+#define m_sub(x,y) rb_funcall(x,'-',1,y)
+#define m_mul(x,y) rb_funcall(x,'*',1,y)
+#define m_div(x,y) rb_funcall(x,'/',1,y)
+#define m_mod(x,y) rb_funcall(x,'%',1,y)
+#define m_divmod(x,y,a,b) \
+ {x = rb_funcall(x,id_divmod,1,y); \
+ a = RARRAY_PTR(x)[0]; b = RARRAY_PTR(x)[0];}
+#define m_pow(x,y) rb_funcall(x,id_pow,1,y)
+#define m_pow_int(x,y) rb_funcall(x,id_pow,1,y)
+
+#define m_abs(x) rb_funcall(x,id_abs,0)
+#define m_minus(x) rb_funcall(x,id_minus,0)
+#define m_reciprocal(x) rb_funcall(x,id_reciprocal,0)
+#define m_square(x) rb_funcall(x,'*',1,x)
+#define m_floor(x) rb_funcall(x,id_floor,0)
+#define m_round(x) rb_funcall(x,id_round,0)
+#define m_ceil(x) rb_funcall(x,id_ceil,0)
+#define m_trunc(x) rb_funcall(x,id_truncate,0)
+#define m_sign(x) rb_funcall(x,id_ufo,1,INT2FIX(0))
+
+#define m_eq(x,y) RTEST(rb_funcall(x,id_eq,1,y))
+#define m_ne(x,y) RTEST(rb_funcall(x,id_ne,1,y))
+#define m_gt(x,y) RTEST(rb_funcall(x,id_gt,1,y))
+#define m_ge(x,y) RTEST(rb_funcall(x,id_ge,1,y))
+#define m_lt(x,y) RTEST(rb_funcall(x,id_lt,1,y))
+#define m_le(x,y) RTEST(rb_funcall(x,id_le,1,y))
+
+#define m_bit_and(x,y) rb_funcall(x,id_bit_and,1,y)
+#define m_bit_or(x,y) rb_funcall(x,id_bit_or, 1,y)
+#define m_bit_xor(x,y) rb_funcall(x,id_bit_xor,1,y)
+#define m_bit_not(x) rb_funcall(x,id_bit_not,0)
+
+#define m_left_shift(x,y) rb_funcall(x,id_left_shift,1,y)
+#define m_right_shift(x,y) rb_funcall(x,id_right_shift,1,y)
+
+#define m_isnan(x) ((rb_respond_to(x,id_nan_p)) ? RTEST(rb_funcall(x,id_nan_p,0)) : 0)
+#define m_isinf(x) ((rb_respond_to(x,id_infinite_p)) ? RTEST(rb_funcall(x,id_infinite_p,0)) : 0)
+#define m_isposinf(x) ((rb_respond_to(x,id_infinite_p)) ? \
+ ((RTEST(rb_funcall(x,id_infinite_p,0))) ? \
+ m_gt(x,INT2FIX(0)) : 0) : 0)
+#define m_isneginf(x) ((rb_respond_to(x,id_infinite_p)) ? \
+ ((RTEST(rb_funcall(x,id_infinite_p,0))) ? \
+ m_lt(x,INT2FIX(0)) : 0) : 0)
+#define m_isfinite(x) ((rb_respond_to(x,id_finite_p)) ? RTEST(rb_funcall(x,id_finite_p,0)) : 0)
+
+#define m_mulsum_init INT2FIX(0)
+
+#define m_sprintf(s,x) robj_sprintf(s,x)
+
+static inline int robj_sprintf(char *s, VALUE x) {
+ VALUE v = rb_funcall(x,rb_intern("to_s"),0);
+ return sprintf(s,"%s",StringValuePtr(v));
+}
+
+#define m_sqrt(x) \
+ rb_funcall(rb_const_get(rb_mKernel,rb_intern("Math")), \
+ rb_intern("sqrt"),1,x);
+
+static inline dtype f_seq(dtype x, dtype y, size_t c)
+{
+ y = m_mul(y,SIZET2NUM(c));
+ return m_add(x,y);
+}
+
+#include "real_accum.h"
diff --git a/ext/numo/narray/numo/types/robject.h b/ext/numo/narray/numo/types/robject.h
new file mode 100644
index 0000000..8a81d6d
--- /dev/null
+++ b/ext/numo/narray/numo/types/robject.h
@@ -0,0 +1,27 @@
+typedef VALUE dtype;
+typedef VALUE rtype;
+#define cT numo_cRObject
+#define cRT cT
+//#define mTM mRObjectMath
+
+#include "float_def.h"
+#include "robj_macro.h"
+
+#define m_min_init (0.0/0.0)
+#define m_max_init (0.0/0.0)
+#define m_extract(x) (*(VALUE*)x)
+#define m_nearly_eq(x,y) robj_nearly_eq(x,y)
+
+inline static int robj_nearly_eq(VALUE vx, VALUE vy)
+{
+ double x, y;
+ x = NUM2DBL(vx);
+ y = NUM2DBL(vy);
+ return (fabs(x-y)<=(fabs(x)+fabs(y))*DBL_EPSILON*2);
+}
+
+/* generates a random number on [0,1)-real-interval */
+inline static dtype m_rand(dtype max)
+{
+ return DBL2NUM(genrand_res53_mix() * max);
+}
diff --git a/ext/numo/narray/numo/types/scomplex.h b/ext/numo/narray/numo/types/scomplex.h
new file mode 100644
index 0000000..e52db3a
--- /dev/null
+++ b/ext/numo/narray/numo/types/scomplex.h
@@ -0,0 +1,44 @@
+typedef scomplex dtype;
+typedef float rtype;
+#define cT numo_cSComplex
+#define cRT numo_cSFloat
+#define mTM numo_mSComplexMath
+
+#include "complex_macro.h"
+
+static inline bool c_nearly_eq(dtype x, dtype y) {
+ return c_abs(c_sub(x,y)) <= (c_abs(x)+c_abs(y))*FLT_EPSILON*2;
+}
+
+#ifdef SFMT_H
+/* generates a random number on [0,1)-real-interval */
+inline static dtype m_rand(dtype max)
+{
+ dtype z;
+ REAL(z) = to_real2(gen_rand32()) * REAL(max);
+ IMAG(z) = to_real2(gen_rand32()) * IMAG(max);
+ return z;
+}
+
+/* generates random numbers from the normal distribution
+ using Box-Muller Transformation.
+ */
+inline static void m_rand_norm(dtype mu, rtype sigma, dtype *a0)
+{
+ rtype x1, x2, w;
+ do {
+ x1 = to_real2(gen_rand32());
+ x1 = x1*2-1;
+ x2 = to_real2(gen_rand32());
+ x2 = x2*2-1;
+ w = x1 * x1 + x2 * x2;
+ } while (w>=1);
+ w = sqrt( (-2*log(w)) / w );
+ REAL(*a0) = x1*w * sigma + REAL(mu);
+ IMAG(*a0) = x2*w * sigma + IMAG(mu);
+}
+#endif
+
+#define M_EPSILON rb_float_new(1.1920928955078125e-07)
+#define M_MIN rb_float_new(1.1754943508222875e-38)
+#define M_MAX rb_float_new(3.4028234663852886e+38)
diff --git a/ext/numo/narray/numo/types/sfloat.h b/ext/numo/narray/numo/types/sfloat.h
new file mode 100644
index 0000000..e516bce
--- /dev/null
+++ b/ext/numo/narray/numo/types/sfloat.h
@@ -0,0 +1,43 @@
+typedef float dtype;
+typedef float rtype;
+#define cT numo_cSFloat
+#define cRT numo_cSFloat
+#define mTM numo_mSFloatMath
+
+#include "float_macro.h"
+
+#ifdef SFMT_H
+/* generates a random number on [0,1)-real-interval */
+inline static dtype m_rand(dtype max)
+{
+ return to_real2(gen_rand32()) * max;
+}
+
+/* generates random numbers from the normal distribution
+ using Box-Muller Transformation.
+ */
+inline static void m_rand_norm(dtype mu, dtype sigma, dtype *a0, dtype *a1)
+{
+ dtype x1, x2, w;
+ do {
+ x1 = to_real2(gen_rand32());
+ x1 = x1*2-1;
+ x2 = to_real2(gen_rand32());
+ x2 = x2*2-1;
+ w = x1 * x1 + x2 * x2;
+ } while (w>=1);
+ w = sqrt( (-2*log(w)) / w );
+ if (a0) {*a0 = x1*w * sigma + mu;}
+ if (a1) {*a1 = x2*w * sigma + mu;}
+}
+#endif
+
+#define m_min_init numo_sfloat_new_dim0(0.0/0.0)
+#define m_max_init numo_sfloat_new_dim0(0.0/0.0)
+
+#define m_extract(x) rb_float_new(*(float*)x)
+#define m_nearly_eq(x,y) (fabs(x-y)<=(fabs(x)+fabs(y))*FLT_EPSILON*2)
+
+#define M_EPSILON rb_float_new(1.1920928955078125e-07)
+#define M_MIN rb_float_new(1.1754943508222875e-38)
+#define M_MAX rb_float_new(3.4028234663852886e+38)
diff --git a/ext/numo/narray/numo/types/uint16.h b/ext/numo/narray/numo/types/uint16.h
new file mode 100644
index 0000000..880c861
--- /dev/null
+++ b/ext/numo/narray/numo/types/uint16.h
@@ -0,0 +1,18 @@
+typedef u_int16_t dtype;
+typedef u_int16_t rtype;
+#define cT numo_cUInt16
+#define cRT cT
+
+#define m_num_to_data(x) ((dtype)NUM2UINT(x))
+#define m_data_to_num(x) UINT2NUM((unsigned int)(x))
+#define m_extract(x) UINT2NUM((unsigned int)*(dtype*)(x))
+#define m_sprintf(s,x) sprintf(s,"%u",(unsigned int)(x))
+
+#include "uint_macro.h"
+
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535)
+#endif
+
+#define M_MIN INT2FIX(0)
+#define M_MAX m_data_to_num(UINT16_MAX)
diff --git a/ext/numo/narray/numo/types/uint32.h b/ext/numo/narray/numo/types/uint32.h
new file mode 100644
index 0000000..8435271
--- /dev/null
+++ b/ext/numo/narray/numo/types/uint32.h
@@ -0,0 +1,18 @@
+typedef u_int32_t dtype;
+typedef u_int32_t rtype;
+#define cT numo_cUInt32
+#define cRT cT
+
+#define m_num_to_data(x) ((dtype)NUM2UINT32(x))
+#define m_data_to_num(x) UINT322NUM((u_int32_t)(x))
+#define m_extract(x) UINT322NUM((u_int32_t)*(dtype*)(x))
+#define m_sprintf(s,x) sprintf(s,"%"PRIu32,(u_int32_t)(x))
+
+#include "uint_macro.h"
+
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295u)
+#endif
+
+#define M_MIN INT2FIX(0)
+#define M_MAX m_data_to_num(UINT32_MAX)
diff --git a/ext/numo/narray/numo/types/uint64.h b/ext/numo/narray/numo/types/uint64.h
new file mode 100644
index 0000000..0ad200e
--- /dev/null
+++ b/ext/numo/narray/numo/types/uint64.h
@@ -0,0 +1,18 @@
+typedef u_int64_t dtype;
+typedef u_int64_t rtype;
+#define cT numo_cUInt64
+#define cRT cT
+
+#define m_num_to_data(x) ((dtype)NUM2UINT64(x))
+#define m_data_to_num(x) UINT642NUM((u_int64_t)(x))
+#define m_extract(x) UINT642NUM((u_int64_t)*(dtype*)(x))
+#define m_sprintf(s,x) sprintf(s,"%"PRIu64,(u_int64_t)(x))
+
+#include "uint_macro.h"
+
+#ifndef UINT64_MAX
+#define UINT64_MAX (18446744073709551615ul)
+#endif
+
+#define M_MIN INT2FIX(0)
+#define M_MAX m_data_to_num(UINT64_MAX)
diff --git a/ext/numo/narray/numo/types/uint8.h b/ext/numo/narray/numo/types/uint8.h
new file mode 100644
index 0000000..4fe24e5
--- /dev/null
+++ b/ext/numo/narray/numo/types/uint8.h
@@ -0,0 +1,18 @@
+typedef u_int8_t dtype;
+typedef u_int8_t rtype;
+#define cT numo_cUInt8
+#define cRT cT
+
+#define m_num_to_data(x) ((dtype)NUM2UINT(x))
+#define m_data_to_num(x) UINT2NUM((unsigned int)(x))
+#define m_extract(x) UINT2NUM((unsigned int)*(dtype*)(x))
+#define m_sprintf(s,x) sprintf(s,"%u",(unsigned int)(x))
+
+#include "uint_macro.h"
+
+#ifndef UINT8_MAX
+#define UINT8_MAX (255)
+#endif
+
+#define M_MIN INT2FIX(0)
+#define M_MAX m_data_to_num(UINT8_MAX)
diff --git a/ext/numo/narray/numo/types/uint_macro.h b/ext/numo/narray/numo/types/uint_macro.h
new file mode 100644
index 0000000..51639ba
--- /dev/null
+++ b/ext/numo/narray/numo/types/uint_macro.h
@@ -0,0 +1,32 @@
+#include "xint_macro.h"
+
+#define m_abs(x) (x)
+#define m_sign(x) (((x)==0) ? 0:1)
+
+static inline dtype int_reciprocal(dtype x) {
+ switch (x) {
+ case 1:
+ return 1;
+ case 0:
+ rb_raise(rb_eZeroDivError, "divided by 0");
+ default:
+ return 0;
+ }
+}
+
+static dtype pow_int(dtype x, int p)
+{
+ dtype r = m_one;
+ switch(p) {
+ case 0: return 1;
+ case 1: return x;
+ case 2: return x*x;
+ case 3: return x*x*x;
+ }
+ while (p) {
+ if (p&1) r *= x;
+ x *= x;
+ p >>= 1;
+ }
+ return r;
+}
diff --git a/ext/numo/narray/numo/types/xint_macro.h b/ext/numo/narray/numo/types/xint_macro.h
new file mode 100644
index 0000000..89fe0ab
--- /dev/null
+++ b/ext/numo/narray/numo/types/xint_macro.h
@@ -0,0 +1,173 @@
+#define m_zero 0
+#define m_one 1
+
+#define m_from_double(x) (x)
+#define m_from_real(x) (x)
+
+#define m_add(x,y) ((x)+(y))
+#define m_sub(x,y) ((x)-(y))
+#define m_mul(x,y) ((x)*(y))
+#define m_div(x,y) ((x)/(y))
+#define m_mod(x,y) ((x)%(y))
+#define m_divmod(x,y,a,b) {a=(x)/(y); b=m_mod(x,y);}
+#define m_pow(x,y) pow_int(x,y)
+#define m_pow_int(x,y) pow_int(x,y)
+
+#define m_bit_and(x,y) ((x)&(y))
+#define m_bit_or(x,y) ((x)|(y))
+#define m_bit_xor(x,y) ((x)^(y))
+#define m_bit_not(x) (~(x))
+
+#define m_minus(x) (-(x))
+#define m_reciprocal(x) int_reciprocal(x)
+#define m_square(x) ((x)*(x))
+
+#define m_eq(x,y) ((x)==(y))
+#define m_ne(x,y) ((x)!=(y))
+#define m_gt(x,y) ((x)>(y))
+#define m_ge(x,y) ((x)>=(y))
+#define m_lt(x,y) ((x)<(y))
+#define m_le(x,y) ((x)<=(y))
+#define m_left_shift(x,y) ((x)<<(y))
+#define m_right_shift(x,y) ((x)>>(y))
+
+#define m_isnan(x) 0
+
+#define m_mulsum(x,y,z) {z += x*y;}
+#define m_mulsum_init INT2FIX(0)
+#define m_cumsum(x,y) {x += y;}
+#define m_cumprod(x,y) {x *= y;}
+
+#define cmp(a,b) \
+ ((qsort_cast(a)==qsort_cast(b)) ? 0 : \
+ (qsort_cast(a) > qsort_cast(b)) ? 1 : -1)
+#define cmpgt(a,b) \
+ (qsort_cast(a) > qsort_cast(b))
+
+
+static inline dtype f_sum(size_t n, char *p, ssize_t stride)
+{
+ dtype x,y=0;
+ size_t i=n;
+ for (; i--;) {
+ x = *(dtype*)p;
+ y += x;
+ p += stride;
+ }
+ return y;
+}
+
+static inline dtype f_prod(size_t n, char *p, ssize_t stride)
+{
+ dtype x,y=1;
+ size_t i=n;
+ for (; i--;) {
+ x = *(dtype*)p;
+ y *= x;
+ p += stride;
+ }
+ return y;
+}
+
+static inline dtype f_min(size_t n, char *p, ssize_t stride)
+{
+ dtype x,y;
+ size_t i=n;
+
+ y = *(dtype*)p;
+ p += stride;
+ i--;
+ for (; i--;) {
+ x = *(dtype*)p;
+ if (x < y) {
+ y = x;
+ }
+ p += stride;
+ }
+ return y;
+}
+
+static inline dtype f_max(size_t n, char *p, ssize_t stride)
+{
+ dtype x,y;
+ size_t i=n;
+
+ y = *(dtype*)p;
+ p += stride;
+ i--;
+ for (; i--;) {
+ x = *(dtype*)p;
+ if (x > y) {
+ y = x;
+ }
+ p += stride;
+ }
+ return y;
+}
+
+static inline size_t f_min_index(size_t n, char *p, ssize_t stride)
+{
+ dtype x, y;
+ size_t i, j=0;
+
+ y = *(dtype*)p;
+ for (i=1; i<n; i++) {
+ x = *(dtype*)(p+i*stride);
+ if (x < y) {
+ y = x;
+ j = i;
+ }
+ }
+ return j;
+}
+
+static inline size_t f_max_index(size_t n, char *p, ssize_t stride)
+{
+ dtype x, y;
+ size_t i, j=0;
+
+ y = *(dtype*)p;
+ for (i=1; i<n; i++) {
+ x = *(dtype*)(p+i*stride);
+ if (x > y) {
+ y = x;
+ j = i;
+ }
+ }
+ return j;
+}
+
+static inline void
+f_minmax(size_t n, char *p, ssize_t stride, dtype* amin, dtype* amax)
+{
+ dtype x,min,max;
+ size_t i=n;
+
+ min = max = *(dtype*)p;
+ p += stride;
+ for (i--; i--;) {
+ x = *(dtype*)p;
+ if (m_gt(x,max)) {
+ max = x;
+ }
+ if (m_lt(x,min)) {
+ min = x;
+ }
+ p += stride;
+ }
+ *amin = min;
+ *amax = max;
+ return;
+}
+
+static inline dtype f_ptp(size_t n, char *p, ssize_t stride)
+{
+ dtype min,max;
+ f_minmax(n,p,stride,&min,&max);
+ return m_sub(max,min);
+}
+
+static inline double f_seq(double x, double y, double c)
+{
+ return x + y * c;
+}
diff --git a/ext/numo/narray/rand.c b/ext/numo/narray/rand.c
new file mode 100644
index 0000000..97542cb
--- /dev/null
+++ b/ext/numo/narray/rand.c
@@ -0,0 +1,72 @@
+#include "ruby.h"
+#include "numo/narray.h"
+#include "SFMT.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <time.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+int n_bits(u_int64_t a)
+{
+ int i, x, /*xu,*/ xl, n=5;
+ u_int64_t m;
+
+ if (a==0) return 0;
+ //if (a<0) a=-a;
+
+ x = 1<<n;
+ //xu = 1<<(n+1);
+ xl = 0;
+ //printf("%3i, [%3i, %3i], %i\n", i, xu, xl, x);
+
+ for (i=n; i>=0; i--) {
+ m = ~((1<<(x-1))-1);
+ if (m & a) {
+ xl = x;
+ x += 1<<(i-1);
+ } else {
+ //xu = x;
+ x -= 1<<(i-1);
+ }
+ //printf("%3i, [%3i, %3i], %i, 0x%lx, 0x%lx\n", i, xu, xl, x, m, m&a);
+ }
+ return xl;
+}
+
+static u_int64_t
+ random_seed()
+{
+ static int n = 0;
+ struct timeval tv;
+
+ gettimeofday(&tv, 0);
+ return tv.tv_sec ^ tv.tv_usec ^ getpid() ^ n++;
+}
+
+static VALUE
+ nary_s_srand(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE vseed;
+ u_int64_t seed;
+
+ //rb_secure(4);
+ if (rb_scan_args(argc, argv, "01", &vseed) == 0) {
+ seed = random_seed();
+ }
+ else {
+ seed = NUM2UINT64(vseed);
+ }
+ init_gen_rand(seed);
+
+ return Qnil;
+}
+
+void
+Init_nary_rand() {
+ rb_define_singleton_method(cNArray, "srand", nary_s_srand, -1);
+ init_gen_rand(0);
+}
diff --git a/ext/numo/narray/step.c b/ext/numo/narray/step.c
new file mode 100644
index 0000000..a047765
--- /dev/null
+++ b/ext/numo/narray/step.c
@@ -0,0 +1,501 @@
+/*
+ step.c
+ Numerical Array Extension for Ruby
+ (C) Copyright 2007,2013 by Masahiro TANAKA
+*/
+#include <ruby.h>
+#include <math.h>
+
+#include "numo/narray.h"
+
+#if defined(__FreeBSD__) && __FreeBSD__ < 4
+#include <floatingpoint.h>
+#endif
+
+#ifdef HAVE_FLOAT_H
+#include <float.h>
+#endif
+
+#ifdef HAVE_IEEEFP_H
+#include <ieeefp.h>
+#endif
+
+#ifndef DBL_EPSILON
+#define DBL_EPSILON 2.2204460492503131e-16
+#endif
+
+static ID id_beg, id_end, id_len, id_step, id_excl;
+
+//#define EXCL(r) RTEST(rb_ivar_get((r), id_excl))
+#define EXCL(r) RTEST(rb_funcall((r), rb_intern("exclude_end?"), 0))
+
+#define SET_EXCL(r,v) rb_ivar_set((r), id_excl, (v) ? Qtrue : Qfalse)
+
+static void
+step_init(
+ VALUE self,
+ VALUE beg,
+ VALUE end,
+ VALUE step,
+ VALUE len,
+ VALUE excl
+)
+{
+ if (RTEST(len)) {
+ if (!(FIXNUM_P(len) || TYPE(len)==T_BIGNUM)) {
+ rb_raise(rb_eArgError, "length must be Integer");
+ }
+ if (RTEST(rb_funcall(len,rb_intern("<"),1,INT2FIX(0)))) {
+ rb_raise(rb_eRangeError,"length must be non negative");
+ }
+ }
+ rb_ivar_set(self, id_beg, beg);
+ rb_ivar_set(self, id_end, end);
+ rb_ivar_set(self, id_len, len);
+ rb_ivar_set(self, id_step, step);
+ SET_EXCL(self, excl);
+}
+
+VALUE
+nary_step_new(
+ VALUE beg,
+ VALUE end,
+ VALUE step,
+ VALUE len,
+ VALUE excl
+)
+{
+ VALUE self = rb_obj_alloc(na_cStep);
+
+ step_init(self, beg, end, step, len, excl);
+ return self;
+}
+
+VALUE
+nary_step_new2(
+ VALUE range,
+ VALUE step,
+ VALUE len
+)
+{
+ VALUE beg, end, excl;
+ VALUE self = rb_obj_alloc(na_cStep);
+
+ //beg = rb_ivar_get(range, id_beg);
+ beg = rb_funcall(range, id_beg, 0);
+ //end = rb_ivar_get(range, id_end);
+ end = rb_funcall(range, id_end, 0);
+ excl = rb_funcall(range, rb_intern("exclude_end?"), 0);
+
+ step_init(self, beg, end, step, len, excl);
+ return self;
+}
+
+
+/*
+ * call-seq:
+ * Step.new(start, end, step=nil, length=nil) => step
+ * Step.new(range, step=nil, length=nil) => step
+ *
+ * Constructs a step using three parameters among <i>start</i>,
+ * <i>end</i>, <i>step</i> and <i>length</i>. <i>start</i>,
+ * <i>end</i> parameters can be replaced with <i>range</i>. If the
+ * <i>step</i> is omitted (or supplied with nil), then calculated
+ * from <i>length</i> or definded as 1.
+ */
+
+static VALUE
+step_initialize( int argc, VALUE *argv, VALUE self )
+{
+ VALUE a, b=Qnil, c=Qnil, d=Qnil, e=Qnil;
+
+ rb_scan_args(argc, argv, "13", &a, &b, &c, &d);
+ /* Selfs are immutable, so that they should be initialized only once. */
+ if (rb_ivar_defined(self, id_beg)) {
+ rb_name_error(rb_intern("initialize"), "`initialize' called twice");
+ }
+ if (rb_obj_is_kind_of(a,rb_cRange)) {
+ if (argc>3) {
+ rb_raise(rb_eArgError, "extra argument");
+ }
+ d = c;
+ c = b;
+ e = rb_funcall(a, rb_intern("exclude_end?"), 0);
+ //b = rb_ivar_get(a, id_end);
+ b = rb_funcall(a, id_end, 0);
+ //a = rb_ivar_get(a, id_beg);
+ a = rb_funcall(a, id_beg, 0);
+ }
+ step_init(self, a, b, c, d, e);
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * step.begin => obj
+ * step.first => obj
+ *
+ * Returns the start of <i>step</i>.
+ */
+
+static VALUE
+step_first( VALUE self )
+{
+ return rb_ivar_get(self, id_beg);
+}
+
+/*
+ * call-seq:
+ * step.end => obj
+ * step.last => obj
+ *
+ * Returns the object that defines the end of <i>step</i>.
+ */
+
+static VALUE
+step_last( VALUE self )
+{
+ return rb_ivar_get(self, id_end);
+}
+
+/*
+ * call-seq:
+ * step.length => obj
+ * step.size => obj
+ *
+ * Returns the length of <i>step</i>.
+ */
+
+static VALUE
+step_length( VALUE self )
+{
+ return rb_ivar_get(self, id_len);
+}
+
+/*
+ * call-seq:
+ * step.step => obj
+ *
+ * Returns the step of <i>step</i>.
+ */
+
+static VALUE
+step_step( VALUE self )
+{
+ return rb_ivar_get(self, id_step);
+}
+
+/*
+ * call-seq:
+ * step.exclude_end? => true or false
+ *
+ * Returns <code>true</code> if <i>step</i> excludes its end value.
+ */
+static VALUE
+step_exclude_end_p(VALUE self)
+{
+ return RTEST(rb_ivar_get(self, id_excl)) ? Qtrue : Qfalse;
+}
+
+
+/*
+ * call-seq:
+ * step.parameters([array_size]) => [start,step,length]
+ *
+ * Returns the iteration parameters of <i>step</i>. If
+ * <i>array_sizse</i> is given, negative array index is considered.
+ */
+
+void
+nary_step_array_index(VALUE self, size_t ary_size,
+ size_t *plen, ssize_t *pbeg, ssize_t *pstep)
+{
+ size_t len;
+ ssize_t beg=0, step=1;
+ VALUE vbeg, vend, vstep, vlen;
+ ssize_t end=ary_size;
+
+ //vbeg = rb_ivar_get(self, id_beg);
+ //vend = rb_ivar_get(self, id_end);
+ vlen = rb_ivar_get(self, id_len);
+ vstep = rb_ivar_get(self, id_step);
+ vbeg = rb_funcall(self, id_beg, 0);
+ vend = rb_funcall(self, id_end, 0);
+ //vlen = rb_funcall(self, id_len, 0);
+ //vstep = rb_funcall(self, id_step, 0);
+
+ if (RTEST(vbeg)) {
+ beg = NUM2SSIZET(vbeg);
+ if (beg<0) {
+ beg += ary_size;
+ }
+ }
+ if (RTEST(vend)) {
+ end = NUM2SSIZET(vend);
+ if (end<0) {
+ end += ary_size;
+ }
+ }
+
+ //puts("pass 1");
+
+ if (RTEST(vlen)) {
+ len = NUM2SIZET(vlen);
+ if (len>0) {
+ if (RTEST(vstep)) {
+ step = NUM2SSIZET(step);
+ if (RTEST(vbeg)) {
+ if (RTEST(vend)) {
+ rb_raise( rb_eStandardError, "verbose Step object" );
+ } else {
+ end = beg + step*(len-1);
+ }
+ } else {
+ if (RTEST(vend)) {
+ if (EXCL(self)) {
+ if (step>0) end--;
+ if (step<0) end++;
+ }
+ beg = end - step*(len-1);
+ } else {
+ beg = 0;
+ end = step*(len-1);
+ }
+ }
+ } else { // no step
+ step = 1;
+ if (RTEST(vbeg)) {
+ if (RTEST(vend)) {
+ if (EXCL(self)) {
+ if (beg<end) end--;
+ if (beg>end) end++;
+ }
+ if (len>1)
+ step = (end-beg)/(len-1);
+ } else {
+ end = beg + (len-1);
+ }
+ } else {
+ if (RTEST(vend)) {
+ if (EXCL(self)) {
+ end--;
+ }
+ beg = end - (len-1);
+ } else {
+ beg = 0;
+ end = len-1;
+ }
+ }
+ }
+ }
+ } else { // no len
+ if (RTEST(vstep)) {
+ step = NUM2SSIZET(vstep);
+ } else {
+ step = 1;
+ }
+ if (step>0) {
+ if (!RTEST(vbeg)) {
+ beg = 0;
+ }
+ if (!RTEST(vend)) {
+ end = ary_size-1;
+ }
+ else if (EXCL(self)) {
+ end--;
+ }
+ if (beg<=end) {
+ len = (end-beg)/step+1;
+ } else {
+ len = 0;
+ }
+ } else if (step<0) {
+ if (!RTEST(vbeg)) {
+ beg = ary_size-1;
+ }
+ if (!RTEST(vend)) {
+ end = 0;
+ }
+ else if (EXCL(self)) {
+ end++;
+ }
+ if (beg>=end) {
+ len = (beg-end)/(-step)+1;
+ } else {
+ len = 0;
+ }
+ } else {
+ rb_raise( rb_eStandardError, "step must be non-zero" );
+ }
+ }
+
+ //puts("pass 2");
+
+ if (beg<0 || beg>=(ssize_t)ary_size ||
+ end<0 || end>=(ssize_t)ary_size) {
+ rb_raise( rb_eRangeError,
+ "beg=%"SZF"d,end=%"SZF"d is out of array size (%"SZF"u)",
+ beg, end, ary_size );
+ }
+ if (plen) *plen = len;
+ if (pbeg) *pbeg = beg;
+ if (pstep) *pstep = step;
+}
+
+
+void
+nary_step_sequence( VALUE self, size_t *plen, double *pbeg, double *pstep )
+{
+ VALUE vbeg, vend, vstep, vlen;
+ double dbeg, dend, dstep=1, dsize, err;
+ size_t size, n;
+
+ //vbeg = rb_ivar_get(self, id_beg);
+ vbeg = rb_funcall(self, id_beg, 0);
+ dbeg = NUM2DBL(vbeg);
+
+ //vend = rb_ivar_get(self, id_end);
+ vend = rb_funcall(self, id_end, 0);
+
+ vlen = rb_ivar_get(self, id_len);
+ vstep = rb_ivar_get(self, id_step);
+ //vlen = rb_funcall(self, id_len ,0);
+ //vstep = rb_funcall(self, id_step,0);
+
+ if (RTEST(vlen)) {
+ size = NUM2SIZET(vlen);
+
+ if (!RTEST(vstep)) {
+ if (RTEST(vend)) {
+ dend = NUM2DBL(vend);
+ if (EXCL(self)) {
+ n = size;
+ } else {
+ n = size-1;
+ }
+ if (n>0) {
+ dstep = (dend-dbeg)/n;
+ } else {
+ dstep = 1;
+ }
+ } else {
+ dstep = 1;
+ }
+ }
+ } else {
+ if (!RTEST(vstep)) {
+ dstep = 1;
+ } else {
+ dstep = NUM2DBL(vstep);
+ }
+ if (RTEST(vend)) {
+ dend = NUM2DBL(vend);
+ err = (fabs(dbeg)+fabs(dend)+fabs(dend-dbeg))/fabs(dstep)*DBL_EPSILON;
+ if (err>0.5) err=0.5;
+ dsize = (dend-dbeg)/dstep;
+ if (EXCL(self))
+ dsize -= err;
+ else
+ dsize += err;
+ dsize = floor(dsize) + 1;
+ if (dsize<0) dsize=0;
+ if (isinf(dsize) || isnan(dsize)) {
+ rb_raise(rb_eArgError, "not finite size");
+ }
+ size = dsize;
+ } else {
+ rb_raise(rb_eArgError, "cannot determine length argument");
+ }
+ }
+
+ if (plen) *plen = size;
+ if (pbeg) *pbeg = dbeg;
+ if (pstep) *pstep = dstep;
+}
+
+/*
+static VALUE
+step_each( VALUE self )
+{
+ VALUE a;
+ double beg, step;
+ size_t i, size;
+
+ a = nary_step_parameters( self, Qnil );
+ beg = NUM2DBL(RARRAY_PTR(a)[0]);
+ step = NUM2DBL(RARRAY_PTR(a)[1]);
+ size = NUM2SIZET(RARRAY_PTR(a)[2]);
+
+ for (i=0; i<size; i++) {
+ rb_yield(rb_float_new(beg+i*step));
+ }
+ return self;
+}
+*/
+
+static VALUE
+range_with_step( VALUE range, VALUE step )
+{
+ return nary_step_new2( range, step, Qnil );
+}
+
+static VALUE
+range_with_length( VALUE range, VALUE len )
+{
+ return nary_step_new2( range, Qnil, len );
+}
+
+
+static VALUE
+nary_s_step( int argc, VALUE *argv, VALUE mod )
+{
+ VALUE self = rb_obj_alloc(na_cStep);
+ step_initialize(argc, argv, self);
+ return self;
+}
+
+
+VALUE
+nary_is_sequence( VALUE arg )
+{
+ if ( rb_obj_is_kind_of(arg, rb_cRange) )
+ return Qtrue;
+ if ( rb_obj_is_kind_of(arg, na_cStep) )
+ return Qtrue;
+ return Qfalse;
+}
+
+
+
+void
+Init_nary_step()
+{
+ na_cStep = rb_define_class_under(cNArray, "Step", rb_cObject);
+ rb_include_module(na_cStep, rb_mEnumerable);
+ rb_define_method(na_cStep, "initialize", step_initialize, -1);
+
+ //rb_define_method(na_cStep, "each", step_each, 0);
+
+ rb_define_method(na_cStep, "first", step_first, 0);
+ rb_define_method(na_cStep, "last", step_last, 0);
+ rb_define_method(na_cStep, "begin", step_first, 0);
+ rb_define_method(na_cStep, "end", step_last, 0);
+ rb_define_method(na_cStep, "step", step_step, 0);
+ rb_define_method(na_cStep, "length", step_length, 0);
+ rb_define_method(na_cStep, "size", step_length, 0);
+ rb_define_method(na_cStep, "exclude_end?", step_exclude_end_p, 0);
+ //rb_define_method(na_cStep, "to_s", step_to_s, 0);
+ //rb_define_method(na_cStep, "inspect", step_inspect, 0);
+ //rb_define_method(na_cStep, "parameters", nary_step_parameters, 1);
+
+ rb_define_method(rb_cRange, "%", range_with_step, 1);
+ rb_define_method(rb_cRange, "*", range_with_length, 1);
+
+ rb_define_singleton_method(cNArray, "step", nary_s_step, -1);
+
+ id_beg = rb_intern("begin");
+ id_end = rb_intern("end");
+ id_len = rb_intern("length");
+ id_step = rb_intern("step");
+ id_excl = rb_intern("excl");
+}
diff --git a/ext/numo/narray/struct.c b/ext/numo/narray/struct.c
new file mode 100644
index 0000000..6cc5f6e
--- /dev/null
+++ b/ext/numo/narray/struct.c
@@ -0,0 +1,885 @@
+/*
+ strut.c
+ Numerical Array Extension for Ruby
+ (C) Copyright 1999-2017 by Masahiro TANAKA
+*/
+#include <ruby.h>
+#include "numo/narray.h"
+#include "numo/template.h"
+
+#define cT numo_cStruct
+VALUE cT;
+
+static VALUE
+nst_allocate(VALUE self)
+{
+ narray_t *na;
+ char *ptr;
+ VALUE velmsz;
+
+ GetNArray(self,na);
+
+ switch(NA_TYPE(na)) {
+ case NARRAY_DATA_T:
+ ptr = NA_DATA_PTR(na);
+ if (na->size > 0 && ptr == NULL) {
+ velmsz = rb_const_get(CLASS_OF(self), rb_intern("element_byte_size"));
+ ptr = xmalloc(NUM2SIZET(velmsz) * na->size);
+ NA_DATA_PTR(na) = ptr;
+ }
+ break;
+ case NARRAY_VIEW_T:
+ rb_funcall(NA_VIEW_DATA(na), rb_intern("allocate"), 0);
+ break;
+ case NARRAY_FILEMAP_T:
+ //ptr = ((narray_filemap_t*)na)->ptr;
+ // to be implemented
+ default:
+ rb_bug("invalid narray type : %d",NA_TYPE(na));
+ }
+ return self;
+}
+
+
+static inline VALUE
+nst_definitions(VALUE nst)
+{
+ return rb_const_get(nst, rb_intern("DEFINITIONS"));
+}
+
+static VALUE
+nst_definition(VALUE nst, VALUE idx)
+{
+ long i;
+ VALUE def = nst_definitions(CLASS_OF(nst));
+ long len = RARRAY_LEN(def);
+
+ if (TYPE(idx) == T_STRING || TYPE(idx) == T_SYMBOL) {
+ ID id = rb_to_id(idx);
+ for (i=0; i<len; i++) {
+ VALUE key = RARRAY_AREF(RARRAY_AREF(def,i),0);
+ if (SYM2ID(key) == id) {
+ return RARRAY_AREF(def,i);
+ }
+ }
+ } else if (rb_obj_is_kind_of(idx,rb_cNumeric)) {
+ i = NUM2LONG(idx);
+ if (i<-len || i>=len) {
+ rb_raise(rb_eIndexError,"offset %ld out of range of struct(size:%ld)", i, len);
+ }
+ return RARRAY_AREF(def,i);
+ }
+ return Qnil;
+}
+
+
+
+void na_copy_array_structure(VALUE self, VALUE view);
+
+VALUE
+na_make_view_struct(VALUE self, VALUE dtype, VALUE offset)
+{
+ size_t i, n;
+ int j, k, ndim;
+ size_t *shape;
+ size_t *idx1, *idx2;
+ ssize_t stride;
+ stridx_t *stridx;
+ narray_t *na, *nt;
+ narray_view_t *na1, *na2;
+ VALUE klass;
+ volatile VALUE view;
+
+ GetNArray(self,na);
+
+ // build from Numo::Struct
+ if (rb_obj_is_kind_of(dtype,cNArray)) {
+ GetNArray(dtype,nt);
+ ndim = na->ndim + nt->ndim;
+ shape = ALLOCA_N(size_t,ndim);
+ // struct dimensions
+ for (j=0; j<na->ndim; j++) {
+ shape[j] = na->shape[j];
+ }
+ // member dimension
+ for (j=na->ndim,k=0; j<ndim; j++,k++) {
+ shape[j] = nt->shape[k];
+ }
+ klass = CLASS_OF(dtype);
+ stridx = ALLOC_N(stridx_t, ndim);
+ stride = na_dtype_elmsz(klass);
+ for (j=ndim,k=nt->ndim; k; ) {
+ SDX_SET_STRIDE(stridx[--j],stride);
+ stride *= nt->shape[--k];
+ }
+ } else {
+ ndim = na->ndim;
+ shape = ALLOCA_N(size_t,ndim);
+ for (j=0; j<ndim; j++) {
+ shape[j] = na->shape[j];
+ }
+ klass = CLASS_OF(self);
+ if (TYPE(dtype)==T_CLASS) {
+ if (RTEST(rb_class_inherited_p(dtype,cNArray))) {
+ klass = dtype;
+ }
+ }
+ stridx = ALLOC_N(stridx_t, ndim);
+ }
+
+ view = na_s_allocate_view(klass);
+ na_copy_flags(self, view);
+ GetNArrayView(view, na2);
+ na_setup_shape((narray_t*)na2, ndim, shape);
+ na2->stridx = stridx;
+
+ switch(na->type) {
+ case NARRAY_DATA_T:
+ case NARRAY_FILEMAP_T:
+ stride = nary_element_stride(self);
+ for (j=na->ndim; j--;) {
+ SDX_SET_STRIDE(na2->stridx[j], stride);
+ stride *= na->shape[j];
+ }
+ na2->offset = 0;
+ na2->data = self;
+ break;
+ case NARRAY_VIEW_T:
+ GetNArrayView(self, na1);
+ for (j=na1->base.ndim; j--; ) {
+ if (SDX_IS_INDEX(na1->stridx[j])) {
+ n = na1->base.shape[j];
+ idx1 = SDX_GET_INDEX(na1->stridx[j]);
+ idx2 = ALLOC_N(size_t, na1->base.shape[j]);
+ for (i=0; i<n; i++) {
+ idx2[i] = idx1[i];
+ }
+ SDX_SET_INDEX(na2->stridx[j],idx2);
+ } else {
+ na2->stridx[j] = na1->stridx[j];
+ }
+ }
+ na2->offset = na1->offset;
+ na2->data = na1->data;
+ break;
+ }
+
+ if (RTEST(offset)) {
+ na2->offset += NUM2SIZET(offset);
+ }
+
+ return view;
+}
+
+
+VALUE
+nst_field_view(VALUE self, VALUE idx)
+{
+ VALUE def, type, ofs;
+
+ def = nst_definition(self, idx);
+ if (!RTEST(def)) {
+ idx = rb_funcall(idx, rb_intern("to_s"), 0);
+ rb_raise(rb_eTypeError, "Invalid field: '%s' for struct %s",
+ StringValuePtr(idx), rb_class2name(CLASS_OF(self)));
+ }
+ type = RARRAY_AREF(def,1);
+ ofs = RARRAY_AREF(def,2);
+ return na_make_view_struct(self, type, ofs);
+}
+
+VALUE
+nst_field(VALUE self, VALUE idx)
+{
+ VALUE obj;
+ narray_view_t *nv;
+
+ obj = nst_field_view(self,idx);
+ GetNArrayView(obj,nv);
+ if (nv->base.ndim==0) {
+ obj = rb_funcall(obj,rb_intern("extract"),0);
+ }
+ return obj;
+}
+
+VALUE
+nst_field_set(VALUE self, VALUE idx, VALUE other)
+{
+ VALUE obj;
+
+ obj = nst_field_view(self,idx);
+ rb_funcall(obj,rb_intern("store"),1,other);
+ return other;
+}
+
+
+static VALUE
+nst_method_missing(int argc, VALUE *argv, VALUE self)
+{
+ VALUE s, tag, obj;
+
+ if (argc == 2) {
+ s = rb_sym_to_s(argv[0]);
+ if (RSTRING_PTR(s)[RSTRING_LEN(s)-1] == '=') {
+ tag = rb_str_intern(rb_str_new(RSTRING_PTR(s), RSTRING_LEN(s)-1));
+ obj = nst_field(self, tag);
+ if (RTEST(obj)) {
+ rb_funcall(obj, rb_intern("store"), 1, argv[1]);
+ return argv[1];
+ }
+ }
+ return rb_call_super(argc,argv);
+ }
+ if (argc == 1) {
+ obj = nst_field(self,argv[0]);
+ if (RTEST(obj)) {
+ return obj;
+ }
+ }
+ return rb_call_super(argc,argv);
+}
+
+
+/*
+ Foo = Numo::Struct.new {
+ int8 :byte
+ float64 :float, [2,2]
+ dcomplex :compl
+ }
+ */
+static VALUE
+nst_s_new(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE name=Qnil, rest, size;
+ VALUE st, members;
+ ID id;
+
+ rb_scan_args(argc, argv, "0*", &rest);
+ if (RARRAY_LEN(rest)>0) {
+ name = RARRAY_AREF(rest,0);
+ if (!NIL_P(name)) {
+ VALUE tmp = rb_check_string_type(name);
+ if (!NIL_P(tmp)) {
+ rb_ary_shift(rest);
+ } else {
+ name = Qnil;
+ }
+ }
+ }
+
+ if (NIL_P(name)) {
+ st = rb_define_class_id(name, klass);
+ rb_funcall(klass, rb_intern("inherited"), 1, st);
+ }
+ else {
+ char *cname = StringValuePtr(name);
+ id = rb_intern(cname);
+ if (!rb_is_const_id(id)) {
+ rb_name_error(id, "identifier %s needs to be constant", cname);
+ }
+ if (rb_const_defined_at(klass, id)) {
+ rb_warn("redefining constant Struct::%s", cname);
+ rb_mod_remove_const(klass, ID2SYM(id));
+ }
+ st = rb_define_class_under(klass, rb_id2name(id), klass);
+ }
+
+ rb_iv_set(st, "__members__", rb_ary_new());
+ rb_iv_set(st, "__offset__", INT2FIX(0));
+
+ if (rb_block_given_p()) {
+ rb_mod_module_eval(0, 0, st);
+ }
+
+ size = rb_iv_get(st, "__offset__");
+ members = rb_iv_get(st, "__members__");
+ //printf("size=%d\n",NUM2INT(size));
+ rb_define_const(st, CONTIGUOUS_STRIDE, size);
+ rb_define_const(st, ELEMENT_BYTE_SIZE, size);
+ rb_define_const(st, ELEMENT_BIT_SIZE, rb_funcall(size,'*',1,INT2FIX(8)));
+
+ OBJ_FREEZE(members);
+ rb_define_const(st, "DEFINITIONS", members);
+
+ rb_define_singleton_method(st, "new", rb_class_new_instance, -1);
+ //rb_define_singleton_method(st, "[]", rb_class_new_instance, -1);
+ rb_define_method(st, "allocate", nst_allocate, 0);
+
+ return st;
+}
+
+
+static VALUE
+nstruct_add_type(VALUE type, int argc, VALUE *argv, VALUE nst)
+{
+ VALUE ofs, size;
+ ID id;
+ int i;
+ VALUE name=Qnil;
+ size_t *shape=NULL;
+ int ndim=0;
+ ssize_t stride;
+ narray_view_t *nt;
+ int j;
+
+ for (i=0; i<argc; i++) {
+ switch(TYPE(argv[i])) {
+ case T_STRING:
+ case T_SYMBOL:
+ if (NIL_P(name)) {
+ name = argv[i];
+ break;
+ }
+ rb_raise(rb_eArgError,"multiple name in struct definition");
+ case T_ARRAY:
+ if (shape) {
+ rb_raise(rb_eArgError,"multiple shape in struct definition");
+ }
+ ndim = RARRAY_LEN(argv[i]);
+ if (ndim > NA_MAX_DIMENSION) {
+ rb_raise(rb_eArgError,"too large number of dimensions");
+ }
+ if (ndim == 0) {
+ rb_raise(rb_eArgError,"array is empty");
+ }
+ shape = ALLOCA_N(size_t, ndim);
+ na_array_to_internal_shape(Qnil, argv[i], shape);
+ break;
+ }
+ }
+
+ id = rb_to_id(name);
+ name = ID2SYM(id);
+ if (rb_obj_is_kind_of(type,cNArray)) {
+ narray_t *na;
+ GetNArray(type,na);
+ type = CLASS_OF(type);
+ ndim = na->ndim;
+ shape = na->shape;
+ }
+ type = nary_view_new(type,ndim,shape);
+ GetNArrayView(type,nt);
+
+ nt->stridx = ALLOC_N(stridx_t,ndim);
+ stride = na_dtype_elmsz(CLASS_OF(type));
+ for (j=ndim; j--; ) {
+ SDX_SET_STRIDE(nt->stridx[j], stride);
+ stride *= shape[j];
+ }
+
+ ofs = rb_iv_get(nst, "__offset__");
+ nt->offset = NUM2SIZET(ofs);
+
+ size = rb_funcall(type, rb_intern("byte_size"), 0);
+ rb_iv_set(nst, "__offset__", rb_funcall(ofs,'+',1,size));
+ rb_ary_push(rb_iv_get(nst,"__members__"),
+ rb_ary_new3(4,name,type,ofs,size)); // <- field definition
+ return Qnil;
+}
+
+
+static VALUE
+nst_extract(VALUE self)
+{
+ return self;
+}
+
+
+static void
+iter_nstruct_to_a(na_loop_t *const lp)
+{
+ long i, len;
+ VALUE opt, types, defs, def;
+ VALUE elmt, velm, vary;
+ size_t ofs, pos;
+ narray_view_t *ne;
+
+ opt = lp->option;
+ types = RARRAY_AREF(opt,0);
+ defs = RARRAY_AREF(opt,1);
+ pos = lp->args[0].iter[0].pos;
+
+ len = RARRAY_LEN(types);
+ vary = rb_ary_new2(len);
+
+ for (i=0; i<len; i++) {
+ def = RARRAY_AREF(defs,i);
+ ofs = NUM2SIZET(RARRAY_AREF(def,2));
+ //ofs = NUM2SIZET(RARRAY_AREF(ofsts,i));
+ elmt = RARRAY_AREF(types,i);
+ GetNArrayView(elmt,ne);
+ ne->offset = pos + ofs;
+ if (ne->base.ndim==0) {
+ velm = rb_funcall(elmt,rb_intern("extract"),0);
+ } else {
+ velm = rb_funcall(elmt,rb_intern("to_a"),0);
+ }
+ rb_ary_push(vary, velm);
+ }
+ rb_ary_push(lp->args[1].value, vary);
+}
+
+static VALUE
+na_original_data(VALUE self)
+{
+ narray_t *na;
+ narray_view_t *nv;
+
+ GetNArray(self,na);
+ switch(na->type) {
+ case NARRAY_VIEW_T:
+ GetNArrayView(self, nv);
+ return nv->data;
+ }
+ return self;
+}
+
+static VALUE
+nst_create_member_views(VALUE self)
+{
+ VALUE defs, def, types, type, elmt;
+ long i, len;
+ narray_view_t *ne;
+
+ defs = nst_definitions(CLASS_OF(self));
+ len = RARRAY_LEN(defs);
+ types = rb_ary_new2(len);
+ //ofsts = rb_ary_new2(len);
+ for (i=0; i<len; i++) {
+ def = RARRAY_AREF(defs,i);
+ type = RARRAY_AREF(def,1);
+ //ofst = RARRAY_AREF(def,2);
+ elmt = na_make_view(type);
+ rb_ary_push(types, elmt);
+ //rb_ary_push(ofsts, ofst);
+ GetNArrayView(elmt,ne);
+ ne->data = na_original_data(self);
+ }
+ return rb_assoc_new(types,defs);
+}
+
+static VALUE
+nary_struct_to_a(VALUE self)
+{
+ volatile VALUE opt;
+ ndfunc_arg_in_t ain[3] = {{Qnil,0},{sym_loop_opt},{sym_option}};
+ ndfunc_arg_out_t aout[1] = {{rb_cArray,0}}; // dummy?
+ ndfunc_t ndf = {iter_nstruct_to_a, NO_LOOP, 3, 1, ain, aout};
+
+ opt = nst_create_member_views(self);
+ return na_ndloop_cast_narray_to_rarray(&ndf, self, opt);
+}
+
+
+
+// ---
+static size_t
+check_array(VALUE item) {
+ narray_t *na;
+
+ if (TYPE(item) == T_ARRAY) {
+ return 1;
+ }
+ if (RTEST(rb_obj_is_kind_of(item, cNArray))) {
+ GetNArray(item,na);
+ if (na->ndim == 1) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ return 0;
+}
+
+static size_t
+check_array_1d(VALUE item, size_t size) {
+ narray_t *na;
+ size_t i, len;
+
+ if (TYPE(item) == T_ARRAY) {
+ len = RARRAY_LEN(item);
+ if (size != len) {
+ return 0;
+ }
+ for (i=0; i<len; i++) {
+ if (!check_array(RARRAY_AREF(item,i))) {
+ return 0;
+ }
+ }
+ return 1;
+ }
+ if (RTEST(rb_obj_is_kind_of(item, cNArray))) {
+ GetNArray(item,na);
+ if (na->ndim == 1 && na->size == size) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ return 0;
+}
+
+VALUE
+nst_check_compatibility(VALUE nst, VALUE ary)
+{
+ VALUE defs, def, type, item;
+ long len, i;
+ narray_t *nt;
+
+ if (TYPE(ary) != T_ARRAY) {
+ if (nst==CLASS_OF(ary)) { // same Struct
+ return Qtrue;
+ }
+ return Qfalse;
+ }
+ defs = nst_definitions(nst);
+ len = RARRAY_LEN(defs);
+
+ if (len != RARRAY_LEN(ary)) {
+ //puts("pass2");
+ return Qfalse;
+ }
+ for (i=0; i<len; i++) {
+ def = RARRAY_AREF(defs,i);
+ type = RARRAY_AREF(def,1);
+ GetNArray(type,nt);
+ item = RARRAY_AREF(ary,i);
+ if (nt->ndim == 0) {
+ if (check_array(item)) {
+ //puts("pass3");
+ return Qfalse;
+ }
+ } else if (nt->ndim == 1) {
+ if (!check_array_1d(item, nt->size)) {
+ //puts("pass4");
+ return Qfalse;
+ }
+ } else {
+ // multi-dimension member
+ //volatile VALUE vnc;
+ //na_compose_t *nc;
+ VALUE vnc;
+ narray_t *nc;
+ int j;
+
+ //vnc = na_ary_composition(item);
+ //Data_Get_Struct(vnc, na_compose_t, nc);
+ vnc = na_s_new_like(cNArray, item);
+ GetNArray(vnc,nc);
+ if (nt->ndim != nc->ndim) {
+ return Qfalse;
+ }
+ for (j=0; j<nc->ndim; j++) {
+ if (nc->shape[j] != nt->shape[j]) {
+ return Qfalse;
+ }
+ }
+ return Qtrue;
+ }
+ }
+ return Qtrue;
+}
+
+
+
+VALUE na_ary_composition_for_struct(VALUE nstruct, VALUE ary);
+
+// ------
+static void
+iter_nstruct_from_a(na_loop_t *const lp)
+{
+ long i, len;
+ VALUE ary;
+ VALUE types, defs, def;
+ VALUE elmt, item;
+ size_t ofs;
+ narray_view_t *ne;
+
+ types = RARRAY_AREF(lp->option,0);
+ defs = RARRAY_AREF(lp->option,1);
+
+ len = RARRAY_LEN(types);
+ ary = lp->args[1].value;
+ //rb_p(CLASS_OF(ary));rb_p(ary);
+
+ for (i=0; i<len; i++) {
+ def = RARRAY_AREF(defs,i);
+ ofs = NUM2SIZET(RARRAY_AREF(def,2));
+ elmt = RARRAY_AREF(types,i);
+ GetNArrayView(elmt,ne);
+ ne->offset = lp->args[0].iter[0].pos + ofs;
+ item = RARRAY_AREF(ary,i);
+ //rb_p(ary);
+ //rb_p(item);
+ //rb_p(elmt);
+ //abort();
+ rb_funcall(elmt, rb_intern("store"), 1, item);
+ }
+}
+
+static VALUE
+nary_struct_cast_array(VALUE klass, VALUE rary)
+{
+ //volatile VALUE vnc, nary;
+ VALUE nary;
+ narray_t *na;
+ //na_compose_t *nc;
+ VALUE opt;
+ ndfunc_arg_in_t ain[3] = {{OVERWRITE,0},{rb_cArray,0},{sym_option}};
+ ndfunc_t ndf = {iter_nstruct_from_a, NO_LOOP, 3, 0, ain, 0};
+
+ //fprintf(stderr,"rary:");rb_p(rary);
+ //fprintf(stderr,"class_of(rary):");rb_p(CLASS_OF(rary));
+
+ //vnc = na_ary_composition_for_struct(klass, rary);
+ //Data_Get_Struct(vnc, na_compose_t, nc);
+ //nary = nary_new(klass, nc->ndim, nc->shape);
+ nary = na_s_new_like(klass, rary);
+ GetNArray(nary,na);
+ //fprintf(stderr,"na->size=%lu\n",na->size);
+ //fprintf(stderr,"na->ndim=%d\n",na->ndim);
+ if (na->size>0) {
+ opt = nst_create_member_views(nary);
+ rb_funcall(nary, rb_intern("allocate"), 0);
+ na_ndloop_store_rarray2(&ndf, nary, rary, opt);
+ }
+ return nary;
+}
+
+static inline VALUE
+nary_struct_s_cast(VALUE klass, VALUE rary)
+{
+ return nary_struct_cast_array(klass, rary);
+}
+
+
+
+static void
+iter_struct_store_struct(na_loop_t *const lp)
+{
+ size_t i, s1, s2;
+ char *p1, *p2;
+ size_t *idx1, *idx2;
+ size_t elmsz;
+ char *x, *y;
+
+ INIT_COUNTER(lp, i);
+ INIT_PTR_IDX(lp, 0, p1, s1, idx1);
+ INIT_PTR_IDX(lp, 1, p2, s2, idx2);
+ INIT_ELMSIZE(lp, 0, elmsz);
+ if (idx2) {
+ if (idx1) {
+ for (; i--;) {
+ x = (char*)(p1+*idx1); idx1++;
+ y = (char*)(p2+*idx2); idx2++;
+ memcpy(x,y,elmsz);
+ }
+ } else {
+ for (; i--;) {
+ x = (char*)p1; p1+=s1;
+ y = (char*)(p2+*idx2); idx2++;
+ memcpy(x,y,elmsz);
+ }
+ }
+ } else {
+ if (idx1) {
+ for (; i--;) {
+ x = (char*)(p1+*idx1); idx1++;
+ y = (char*)p2; p2+=s2;
+ memcpy(x,y,elmsz);
+ }
+ } else {
+ for (; i--;) {
+ x = (char*)p1; p1+=s1;
+ y = (char*)p2; p2+=s2;
+ memcpy(x,y,elmsz);
+ }
+ }
+ }
+}
+
+
+static VALUE
+nary_struct_store_struct(VALUE self, VALUE obj)
+{
+ ndfunc_arg_in_t ain[2] = {{OVERWRITE,0},{Qnil,0}};
+ ndfunc_t ndf = {iter_struct_store_struct, FULL_LOOP, 2, 0, ain, 0};
+
+ na_ndloop(&ndf, 2, self, obj);
+ return self;
+}
+
+
+
+
+static inline VALUE
+nary_struct_store_array(VALUE self, VALUE obj)
+{
+ return nary_struct_store_struct(self, nary_struct_cast_array(CLASS_OF(self),obj));
+}
+
+/*
+ Store elements to Numo::Struct from other.
+ @overload store(other)
+ @param [Object] other
+ @return [Numo::Struct] self
+*/
+static VALUE
+nary_struct_store(VALUE self, VALUE obj)
+{
+ if (TYPE(obj)==T_ARRAY) {
+ nary_struct_store_array(self,obj);
+ return self;
+ }
+ if (CLASS_OF(self) == CLASS_OF(obj)) {
+ nary_struct_store_struct(self,obj);
+ return self;
+ }
+ rb_raise(nary_eCastError, "unknown conversion from %s to %s",
+ rb_class2name(CLASS_OF(obj)),
+ rb_class2name(CLASS_OF(self)));
+ return self;
+}
+
+
+
+static VALUE
+//iter_struct_inspect(na_loop_t *const lp)
+iter_struct_inspect(char *ptr, size_t pos, VALUE opt)
+{
+ VALUE types, defs, def, name, elmt, vary, v, x;
+ size_t ofs;
+ long i, len;
+ narray_view_t *ne;
+
+ types = RARRAY_AREF(opt,0);
+ defs = RARRAY_AREF(opt,1);
+
+ len = RARRAY_LEN(types);
+ vary = rb_ary_new2(len);
+
+ for (i=0; i<len; i++) {
+ def = RARRAY_AREF(defs,i);
+ name = RARRAY_AREF(def,0);
+ ofs = NUM2SIZET(RARRAY_AREF(def,2));
+ elmt = RARRAY_AREF(types,i);
+ GetNArrayView(elmt,ne);
+ ne->offset = pos + ofs;
+ v = rb_str_concat(rb_sym_to_s(name), rb_str_new2(": "));
+ x = rb_funcall(elmt, rb_intern("format_to_a"), 0); // <-- fix me
+ if (ne->base.ndim==0) {
+ x = rb_funcall(x, rb_intern("first"), 0);
+ }
+ x = rb_funcall(x, rb_intern("to_s"), 0);
+ v = rb_str_concat(v, x);
+ rb_ary_push(vary, v);
+ }
+ v = rb_ary_join(vary, rb_str_new2(", "));
+ v = rb_str_concat(rb_str_new2("["), v);
+ v = rb_str_concat(v, rb_str_new2("]"));
+ return v;
+}
+
+/*
+ Returns a string containing a human-readable representation of NArray.
+ @overload inspect
+ @return [String]
+*/
+VALUE
+nary_struct_inspect(VALUE ary)
+{
+ VALUE opt;
+ opt = nst_create_member_views(ary);
+ return na_ndloop_inspect(ary, iter_struct_inspect, opt);
+}
+
+
+static VALUE
+nst_s_add_type(int argc, VALUE *argv, VALUE mod)
+{
+ if (argc==0)
+ rb_raise(rb_eArgError,
+ "wrong number of arguments (%d for 1)", argc);
+ nstruct_add_type(argv[0],argc-1,argv+1,mod);
+ return Qnil;
+}
+
+
+
+
+#define NST_TYPEDEF(tpname,tpclass) \
+static VALUE \
+nst_s_##tpname(VALUE argc, VALUE *argv, VALUE mod) \
+{ nstruct_add_type(tpclass,argc,argv,mod); \
+ return Qnil; \
+}
+
+NST_TYPEDEF(int8,numo_cInt8)
+NST_TYPEDEF(int16,numo_cInt16)
+NST_TYPEDEF(int32,numo_cInt32)
+NST_TYPEDEF(int64,numo_cInt64)
+NST_TYPEDEF(uint8,numo_cUInt8)
+NST_TYPEDEF(uint16,numo_cUInt16)
+NST_TYPEDEF(uint32,numo_cUInt32)
+NST_TYPEDEF(uint64,numo_cUInt64)
+NST_TYPEDEF(dfloat,numo_cDFloat)
+NST_TYPEDEF(dcomplex,numo_cDComplex)
+NST_TYPEDEF(sfloat,numo_cSFloat)
+NST_TYPEDEF(scomplex,numo_cSComplex)
+
+
+#define rb_define_singleton_alias(klass,name1,name2) \
+ rb_define_alias(rb_singleton_class(klass),name1,name2)
+
+void
+Init_nary_struct()
+{
+ cT = rb_define_class_under(mNumo, "Struct", numo_cNArray);
+ //cNStMember = rb_define_class_under(cT, "Member", rb_cObject);
+
+ //rb_define_alloc_func(cNStMember, nst_member_s_allocate);
+ //rb_define_method(cNStMember, "initialize", nst_member_initialize, -1);
+
+ //rb_undef_alloc_func(cT);
+ rb_define_singleton_method(cT, "new", nst_s_new, -1);
+ rb_define_singleton_method(cT, "add_type", nst_s_add_type, -1);
+ rb_define_singleton_method(cT, "int8", nst_s_int8, -1);
+ rb_define_singleton_method(cT, "int16", nst_s_int16, -1);
+ rb_define_singleton_method(cT, "int32", nst_s_int32, -1);
+ rb_define_singleton_method(cT, "int64", nst_s_int64, -1);
+ rb_define_singleton_method(cT, "uint8", nst_s_uint8, -1);
+ rb_define_singleton_method(cT, "uint16", nst_s_uint16, -1);
+ rb_define_singleton_method(cT, "uint32", nst_s_uint32, -1);
+ rb_define_singleton_method(cT, "uint64", nst_s_uint64, -1);
+ rb_define_singleton_method(cT, "sfloat", nst_s_sfloat, -1);
+ rb_define_singleton_alias (cT, "float32", "sfloat");
+ rb_define_singleton_method(cT, "scomplex", nst_s_scomplex, -1);
+ rb_define_singleton_alias (cT, "complex64", "scomplex");
+ rb_define_singleton_method(cT, "dfloat", nst_s_dfloat, -1);
+ rb_define_singleton_alias (cT, "float64", "dfloat");
+ rb_define_singleton_method(cT, "dcomplex", nst_s_dcomplex, -1);
+ rb_define_singleton_alias (cT, "complex128", "dcomplex");
+
+ rb_define_method(cT, "definition", nst_definition, 1);
+ rb_define_method(cT, "definitions", nst_definitions, 0);
+ rb_define_method(cT, "field", nst_field, 1);
+ rb_define_method(cT, "field_set", nst_field_set, 2);
+ rb_define_method(cT, "extract", nst_extract, 0);
+ rb_define_method(cT, "method_missing", nst_method_missing, -1);
+
+ //rb_define_method(cT, "fill", nary_nstruct_fill, 1);
+
+ //rb_define_method(cT, "debug_print", nary_nstruct_debug_print, 0);
+
+ rb_define_method(cT, "to_a", nary_struct_to_a, 0);
+
+ rb_define_method(cT, "store", nary_struct_store, 1);
+
+ rb_define_method(cT, "inspect", nary_struct_inspect, 0);
+
+ rb_define_singleton_method(cT, "cast", nary_struct_s_cast, 1);
+ rb_define_singleton_method(cT, "[]", nary_struct_s_cast, -2);
+
+ //rb_define_method(cT, "initialize", rb_struct_initialize, -2);
+ //rb_define_method(cT, "initialize_copy", rb_struct_init_copy, 1);
+}
diff --git a/lib/erbpp.rb b/lib/erbpp.rb
new file mode 100644
index 0000000..a454b27
--- /dev/null
+++ b/lib/erbpp.rb
@@ -0,0 +1,294 @@
+require "erb"
+
+class ErbPP
+ ATTRS = []
+
+ class ParamNotSetError < StandardError; end
+
+ def self.define_attrs(attrs)
+ attrs.each do |attr|
+ ivar = ("@"+attr).to_sym
+ define_method(attr){|*a| attr_method(ivar,*a)}
+ end
+ end
+
+ def attr_method(ivar,arg=nil)
+ if arg.nil?
+ instance_variable_get(ivar)
+ else
+ instance_variable_set(ivar,arg)
+ end
+ end
+
+ def initialize(parent,erb_path,opts={})
+ parents.push(parent) if parent
+ @erb_path = erb_path
+ @tmpl = @erb_path
+
+ @opts = opts
+ if @opts.class != Hash
+ raise ArgumentError, "option is not Hash"
+ end
+
+ @opts.each do |k,v|
+ ivar = ("@"+k.to_s).to_sym
+ instance_variable_set(ivar,v)
+ end
+ end
+
+ def load_erb
+ safe_level = nil
+ trim_mode = '%<>'
+ @erb = ERB.new(File.read(@erb_path),safe_level,trim_mode)
+ @erb.filename = @erb_path
+ end
+
+ def parents
+ @parents ||= []
+ end
+
+ def search_method_in_parents(_meth_id)
+ parents.each do |x|
+ if x.has_attr? _meth_id
+ return x
+ end
+ end
+ parents.each do |x|
+ if f = x.search_method_in_parents(_meth_id)
+ return f
+ end
+ end
+ nil
+ end
+
+ def attrs
+ self.class::ATTRS
+ end
+
+ def has_attr?(_meth_id)
+ respond_to?(_meth_id) or attrs.include?(_meth_id.to_s)
+ end
+
+ def check_params(*params)
+ params.each do |x|
+ val = send(x)
+ if !val # || val.empty?
+ raise ParamNotSetError,"parameter #{x.to_s} is not set"
+ end
+ end
+ end
+
+ alias method_missing_alias method_missing
+
+ def method_missing(_meth_id, *args, &block)
+ ivar = "@"+_meth_id.to_s
+ if args.empty? and instance_variable_defined?(ivar)
+ parm = instance_variable_get(ivar)
+ if parm.nil?
+ raise ParamNotSetError,"parameter #{_meth_id.to_s} is not set"
+ end
+ parm
+ elsif args.size == 1 and attrs.include?(_meth_id.to_s)
+ instance_variable_set(ivar,args.first)
+ elsif x = search_method_in_parents(_meth_id)
+ x.send(_meth_id, *args, &block)
+ else
+ method_missing_alias(_meth_id, *args)
+ end
+ end
+
+ def run
+ load_erb unless @erb
+ @erb.run(binding)
+ end
+
+ def result
+ load_erb unless @erb
+ @erb.result(binding)
+ end
+end
+
+# ----------------------------------------------------------------------
+
+class IdVar
+ DEFS = []
+
+ def id_decl
+ "static ID #{@id_var};"
+ end
+
+ def id_assign
+ "#{@id_var} = rb_intern(\"#{@name}\");"
+ end
+
+ def initialize(parent,name,var=nil)
+ @name = name
+ var = name if var.nil?
+ @id_var = "id_"+var.gsub(/\?/,"_p").gsub(/\!/,"_bang")
+ DEFS.push(self)
+ end
+
+ def self.declaration
+ DEFS.map do |x|
+ x.id_decl
+ end
+ end
+
+ def self.assignment
+ DEFS.map do |x|
+ x.id_assign
+ end
+ end
+end
+
+# ----------------------------------------------------------------------
+
+class Function < ErbPP
+ DEFS = []
+
+ attrs = %w[
+ singleton
+ meth
+ n_arg
+ ]
+ define_attrs attrs
+
+ def id_op
+ if op.size == 1
+ "'#{op}'"
+ else
+ "id_#{method}"
+ end
+ end
+
+ def method
+ meth.gsub(/\?/,"_p").gsub(/\!/,"_bang")
+ end
+
+ def initialize(parent,tmpl,**opts)
+ super
+ @aliases = opts[:aliases] || []
+ parent.tmpl_dirs.each do |d|
+ @erb_path = File.join(d, tmpl+".c")
+ break if File.exist?(@erb_path)
+ end
+ DEFS.push(self)
+ end
+
+ def c_method
+ "#{m_prefix}#{method}"
+ end
+
+ def c_iter
+ begin
+ t = "_"+type_name
+ rescue
+ t = ""
+ end
+ "iter#{t}_#{method}"
+ end
+ alias c_iterator c_iter
+
+ def c_func
+ s = singleton ? "_s" : ""
+ begin
+ t = "_"+type_name
+ rescue
+ t = ""
+ end
+ "numo#{t}#{s}_#{method}"
+ end
+ alias c_function c_func
+ alias c_instance_method c_func
+
+ def op_map
+ @op || meth
+ end
+
+ def code
+ result + "\n\n"
+ end
+
+ def definition
+ return nil if n_arg <= -9
+ s = singleton ? "_singleton" : ""
+ check_params(:mod_var, :op_map, :c_func, :n_arg)
+ m = op_map
+ a = ["rb_define#{s}_method(#{mod_var}, \"#{m}\", #{c_func}, #{n_arg});"]
+ @aliases.map{|x| a << "rb_define_alias(#{mod_var}, \"#{x}\", \"#{m}\");"}
+ a
+ end
+
+ def self.codes
+ a = []
+ DEFS.each do |i|
+ x = i.code
+ a.push(x) if x
+ end
+ a
+ end
+
+ def self.definitions
+ a = []
+ DEFS.each do |i|
+ case x = i.definition
+ when Array
+ a.concat(x)
+ when String
+ a.push(x)
+ else
+ raise "unknown definition: #{x}" if x
+ end
+ end
+ a
+ end
+end
+
+class ModuleFunction < Function
+ def definition
+ m = op_map
+ "rb_define_module_function(#{mod_var}, \"#{m}\", #{c_func}, #{n_arg});"
+ end
+end
+
+class NodefFunction < Function
+ def definition
+ nil
+ end
+end
+
+class Alias < ErbPP
+ def initialize(parent, dst, src)
+ super(parent,nil)
+ @dst = dst
+ @src = src
+ Function::DEFS.push(self)
+ end
+
+ def code
+ nil
+ end
+
+ def definition
+ "rb_define_alias(#{mod_var}, \"#{dst}\", \"#{src}\");"
+ end
+end
+
+class Const < ErbPP
+ def initialize(parent,name,value,desc)
+ super(parent,nil)
+ @name = name
+ @value = value
+ @desc = desc
+ Function::DEFS.push(self)
+ end
+
+ def code
+ nil
+ end
+
+ def definition
+ "/*"+desc+"*/\n "+
+ "rb_define_const(#{mod_var},\"#{name}\",#{value});"
+ end
+end
diff --git a/lib/erbpp/line_number.rb b/lib/erbpp/line_number.rb
new file mode 100644
index 0000000..cd51a60
--- /dev/null
+++ b/lib/erbpp/line_number.rb
@@ -0,0 +1,133 @@
+class CountLnString < String
+
+ def initialize(filename)
+ @filename = filename
+ @lnchar = "\n"
+ @buf = ""
+ @str = ""
+ @countln = 1
+ @current = 1
+ super("\n"+report_line)
+ end
+
+ def report_line
+ "#line #{@current} \"#{@filename}\"\n"
+ end
+
+ def concat0(s)
+ ln(caller[0])
+ @buf.concat(s)
+ @str.concat(s)
+ end
+
+ def concat1(s)
+ ln(caller[0])
+ @buf.concat(s)
+ end
+
+ def ln(status=nil)
+ case status
+ when /:(\d+):/
+ n = $1.to_i
+ else
+ n = status.to_i
+ end
+ return if n == @current
+ if @current != @countln || @postpone
+ if /\A\s*\z/ =~ @str || /\A#line / =~ @buf
+ @postpone = true
+ elsif @in_comment
+ @postpone = false
+ else
+ if self[-1] != "\n"
+ concat("\n")
+ end
+ concat(report_line)
+ @postpone = false
+ end
+ end
+ concat(@buf)
+
+ b = @buf.gsub(/".*?(?<!\\)"/,'""')
+ /^.*(\/\*)(.*?)$/ =~ b
+ x = $2
+ /^.*(\*\/)(.*?)$/ =~ b
+ y = $2
+ if x
+ if y
+ if x.size < y.size
+ #:in_comment
+ @in_comment = true
+ else
+ #:out_comment
+ @in_comment = false
+ end
+ else
+ #:in_comment
+ @in_comment = true
+ end
+ else
+ if y
+ #:out_comment
+ @in_comment = false
+ else
+ #:keep
+ end
+ end
+
+ @countln = @current + @buf.count(@lnchar)
+ @current = n
+ @buf = ""
+ @str = ""
+ end
+
+ def d(s)
+ p [s, [x,y], r]
+ r
+ end
+
+ def final
+ concat(@buf)
+ end
+
+end
+
+class ERB
+ alias result_orig result
+
+ def result(b=new_toplevel)
+ src = src_with_cpp_line
+ if @safe_level
+ proc {
+ $SAFE = @safe_level
+ eval(src, b, (@filename || '(erb)'), 0)
+ }.call
+ else
+ #open("tmpout","w"){|f| f.write src} if /dtype/=~@filename
+ eval(src, b, (@filename || '(erb)'), 0)
+ end
+ end
+
+ alias src_orig src
+
+ def src
+ src_with_cpp_line
+ end
+
+ def src_with_cpp_line
+ @src.each_line.with_index.map do |line, num|
+ line.gsub!(/_erbout.concat "/,'_erbout.concat0 "')
+ line.gsub!(/_erbout.concat\(/,'_erbout.concat1(')
+ if num==0
+ # skip
+ elsif num==1
+ f = @filename.dump
+ line.sub!(/_erbout = (''|String\.new);/, "_erbout = CountLnString.new(#{f});")
+ elsif /^; _erbout\.force_encoding/ =~ line
+ line.sub!(/^;/,";_erbout.ln(#{num});")
+ end
+ line
+ end.join+";_erbout.final;"
+ end
+
+end
diff --git a/lib/erbpp/narray_def.rb b/lib/erbpp/narray_def.rb
new file mode 100644
index 0000000..06881d3
--- /dev/null
+++ b/lib/erbpp/narray_def.rb
@@ -0,0 +1,381 @@
+require 'erbpp'
+
+module DefMethod
+
+ def def_id(meth,var=nil)
+ IdVar.new(self, meth, var)
+ end
+
+ def def_method(meth, n_arg, tmpl=nil, opts={})
+ h = {:meth => meth, :n_arg => n_arg}
+ h.merge!(opts)
+ tmpl ||= meth
+ Function.new(self, tmpl, h)
+ end
+
+ def def_singleton(meth, n_arg, tmpl=nil, opts={})
+ def_method(meth, n_arg, tmpl, :singleton => true)
+ end
+
+ def def_alias(dst, src)
+ Alias.new(self, dst, src)
+ end
+
+ def def_allocate(tmpl)
+ h = {:meth => "allocate", :singleton => true}
+ Allocate.new(self, tmpl, h)
+ end
+
+ def binary(meth, ope=nil)
+ ope = meth if ope.nil?
+ def_method(meth, 1, "binary", :op => ope)
+ end
+
+ def binary2(meth, ope=nil)
+ ope = meth if ope.nil?
+ def_method(meth, 1, "binary2", :op =>ope)
+ end
+
+ def unary(meth, ope=nil)
+ def_method(meth, 0, "unary", :op => ope)
+ end
+
+ def pow
+ def_method("pow", 1, "pow", :op => "**")
+ end
+
+ def unary2(meth, dtype, tpclass)
+ h = {:dtype => dtype, :tpclass => tpclass}
+ def_method(meth, 0, "unary2", h)
+ end
+
+ def set2(meth, dtype, tpclass)
+ h = {:dtype => dtype, :tpclass => tpclass}
+ def_method(meth, 1, "set2", h)
+ end
+
+ def cond_binary(meth,op=nil)
+ op = meth unless op
+ def_method(meth, 1, "cond_binary", :op => op)
+ end
+
+ def cond_unary(meth)
+ def_method(meth, 0, "cond_unary")
+ end
+
+ def bit_count(meth)
+ def_method(meth, -1, "bit_count")
+ end
+
+ def bit_reduce(meth, init_bit)
+ h = {:init_bit=>init_bit}
+ def_method(meth, -1, "bit_reduce", h)
+ end
+
+ def accum(meth, dtype, tpclass)
+ h = {:dtype => dtype, :tpclass => tpclass}
+ def_method(meth, -1, "accum", h)
+ end
+
+ def accum_index(meth)
+ def_method(meth, -1, "accum_index")
+ end
+
+ def cum(meth, cmacro)
+ def_method(meth, -1, "cum", cmacro:cmacro)
+ end
+
+ def accum_binary(meth, ope=nil)
+ ope = meth if ope.nil?
+ def_method(meth, -1, "accum_binary", :op => ope)
+ end
+
+ def qsort(tp, dtype, dcast, suffix="")
+ h = {:tp => tp, :dtype => dtype, :dcast => dcast, :suffix => suffix}
+ NodefFunction.new(self, "qsort", h)
+ end
+
+ def def_mod_func(meth, n_arg, tmpl=nil, opts={})
+ h = {:meth => meth, :n_arg => n_arg}
+ h.merge!(opts)
+ tmpl ||= meth
+ ModuleFunction.new(self, tmpl, h)
+ end
+
+ def math(meth, n=1, tmpl=nil)
+ h = {:mod_var => 'mTM'}
+ if tmpl.nil?
+ case n
+ when 1
+ tmpl = "unary_s"
+ when 2
+ tmpl = "binary_s"
+ when 3
+ tmpl = "ternary_s"
+ else
+ raise "invalid n=#{n}"
+ end
+ end
+ def_mod_func(meth, n, tmpl, h)
+ end
+
+ def store_numeric
+ StoreNum.new(self,"store_numeric")
+ end
+
+ def store_array
+ StoreArray.new(self,"store_array")
+ end
+
+ def cast_array
+ CastArray.new(self,"cast_array")
+ end
+
+ def store_from(cname,dtype,macro)
+ Store.new(self,"store_from",cname.downcase,dtype,"numo_c"+cname,macro)
+ end
+
+ def store_bit(cname)
+ Store.new(self,"store_bit",cname.downcase,nil,"numo_c"+cname,nil)
+ end
+
+ def store
+ Function.new(self,"store","store")
+ end
+
+ def find_method(meth)
+ Function::DEFS.find{|x| x.kind_of?(Function) and meth == x.meth }
+ end
+
+ def find_tmpl(meth)
+ Function::DEFS.find{|x| x.kind_of?(Function) and meth == x.tmpl }
+ end
+
+ def cast_func
+ "numo_#{tp}_s_cast"
+ end
+end
+
+# ----------------------------------------------------------------------
+
+class DataType < ErbPP
+ include DefMethod
+
+ def initialize(erb_path, type_file)
+ super(nil, erb_path)
+ @class_alias = []
+ @upcast = []
+ @mod_var = "cT"
+ load_type(type_file) if type_file
+ dirs = template_dir || ["tmpl"]
+ @tmpl_dirs = dirs.map{|d| File.join(File.dirname(erb_path),d)}
+ end
+
+ attr_reader :tmpl_dirs
+
+ def load_type(file)
+ eval File.read(file)
+ end
+
+ attrs = %w[
+ class_name
+ ctype
+ template_dir
+ blas_char
+ complex_class_name
+ complex_type
+ real_class_name
+ real_ctype
+ has_math
+ is_bit
+ is_int
+ is_unsigned
+ is_float
+ is_real
+ is_complex
+ is_object
+ is_comparable
+ is_double_precision
+ mod_var
+ ]
+ define_attrs attrs
+
+ def type_name
+ @type_name ||= class_name.downcase
+ end
+ alias tp type_name
+
+ def type_var
+ @type_var ||= "numo_c"+class_name
+ end
+
+ def math_var
+ @math_var ||= "numo_m"+class_name+"Math"
+ end
+
+ def real_class_name(arg=nil)
+ if arg.nil?
+ @real_class_name ||= class_name
+ else
+ @real_class_name = arg
+ end
+ end
+
+ def real_ctype(arg=nil)
+ if arg.nil?
+ @real_ctype ||= ctype
+ else
+ @real_ctype = arg
+ end
+ end
+
+ def real_type_var
+ @real_type_var ||= "numo_c"+real_class_name
+ end
+
+ def real_type_name
+ @real_type_name ||= real_class_name.downcase
+ end
+
+ def class_alias(*args)
+ @class_alias.concat(args)
+ end
+
+ def upcast(c=nil,t=nil)
+ if c
+ if t
+ t = "numo_c#{t}"
+ else
+ t = "cT"
+ end
+ @upcast << "rb_hash_aset(hCast, numo_c#{c}, #{t});"
+ else
+ @upcast
+ end
+ end
+
+ def upcast_rb(c,t=nil)
+ if t
+ t = "numo_c#{t}"
+ else
+ t = "cT"
+ end
+ if c=="Integer"
+ @upcast << "#ifdef RUBY_INTEGER_UNIFICATION"
+ @upcast << "rb_hash_aset(hCast, rb_cInteger, #{t});"
+ @upcast << "#else"
+ @upcast << "rb_hash_aset(hCast, rb_cFixnum, #{t});"
+ @upcast << "rb_hash_aset(hCast, rb_cBignum, #{t});"
+ @upcast << "#endif"
+ else
+ @upcast << "rb_hash_aset(hCast, rb_c#{c}, #{t});"
+ end
+ end
+end
+
+
+# ----------------------------------------------------------------------
+
+
+class Allocate < Function
+ def definition
+ "rb_define_alloc_func(#{mod_var}, #{c_func});"
+ end
+end
+
+# ----------------------------------------------------------------------
+
+class Store < Function
+ DEFS = []
+
+ def initialize(parent,tmpl,tpname,dtype,tpclass,macro)
+ super(parent,tmpl)
+ @tpname=tpname
+ @dtype=dtype
+ @tpclass=tpclass
+ @macro=macro
+ DEFS.push(self)
+ end
+ attr_reader :tmpl, :tpname, :dtype, :tpclass, :macro
+
+ def c_func
+ "numo_#{tp}_store_#{tpname}"
+ end
+
+ def c_iter
+ "iter_#{tp}_store_#{tpname}"
+ end
+
+ def definition
+ nil
+ end
+
+ def condition(klass)
+ "#{klass}==#{tpclass}"
+ end
+
+ def extract_data(ptr,pos,x)
+ case tpname
+ when "bit"
+ "{BIT_DIGIT b; LOAD_BIT(#{ptr},#{pos},b); x = m_from_real(b);}"
+ when "robject"
+ "#{x} = m_num_to_data(*(#{dtype}*)(#{ptr}+#{pos}))"
+ when /complex/
+ "{#{dtype} *p = (#{dtype}*)(#{ptr}+#{pos}); #{x} = c_new(REAL(*p),IMAG(*p));}"
+ else
+ "#{x} = m_from_real(*(#{dtype}*)(#{ptr}+#{pos}))"
+ end
+ end
+
+ def self.definitions
+ a = []
+ DEFS.each do |x|
+ if x.condition("")
+ if x.tpname == x.parents[0].class_name.downcase
+ a.unshift(x)
+ else
+ a.push(x)
+ end
+ end
+ end
+ a
+ end
+end
+
+class StoreNum < Store
+ def initialize(parent,tmpl)
+ super(parent,tmpl,"numeric",nil,nil,nil)
+ end
+
+ def condition(klass)
+ "IS_INTEGER_CLASS(#{klass}) || #{klass}==rb_cFloat || #{klass}==rb_cComplex"
+ end
+end
+
+class StoreArray < Store
+ def initialize(parent,tmpl)
+ super(parent,tmpl,"array",nil,nil,nil)
+ end
+
+ def c_func
+ "numo_#{tp}_#{tmpl}"
+ end
+
+ def condition(klass)
+ "#{klass}==rb_cArray"
+ end
+end
+
+class CastArray < StoreArray
+ def condition(klass)
+ nil
+ end
+
+ def c_func
+ "numo_#{tp}_cast_#{tpname}"
+ end
+
+ def c_iter
+ "iter_#{tp}_cast_#{tpname}"
+ end
+end
diff --git a/lib/numo/narray.rb b/lib/numo/narray.rb
new file mode 100644
index 0000000..e0e3143
--- /dev/null
+++ b/lib/numo/narray.rb
@@ -0,0 +1,8 @@
+begin
+ major, minor, _ = RUBY_VERSION.split(/\./)
+ require "#{major}.#{minor}/numo/narray.so"
+rescue LoadError
+ require "numo/narray.so"
+end
+
+require "numo/narray/extra"
diff --git a/lib/numo/narray/extra.rb b/lib/numo/narray/extra.rb
new file mode 100644
index 0000000..5e3c99e
--- /dev/null
+++ b/lib/numo/narray/extra.rb
@@ -0,0 +1,1262 @@
+module Numo
+ class NArray
+
+ # Return an unallocated array with the same shape and type as self.
+ def new_narray
+ self.class.new(*shape)
+ end
+
+ # Return an array of zeros with the same shape and type as self.
+ def new_zeros
+ self.class.zeros(*shape)
+ end
+
+ # Return an array of ones with the same shape and type as self.
+ def new_ones
+ self.class.ones(*shape)
+ end
+
+ # Return an array filled with value with the same shape and type as self.
+ def new_fill(value)
+ self.class.new(*shape).fill(value)
+ end
+
+ # Convert angles from radians to degrees.
+ def rad2deg
+ self * (180/Math::PI)
+ end
+
+ # Convert angles from degrees to radians.
+ def deg2rad
+ self * (Math::PI/180)
+ end
+
+ # Flip each row in the left/right direction.
+ # Same as `a[true, (-1..0).step(-1), ...]`.
+ def fliplr
+ reverse(1)
+ end
+
+ # Flip each column in the up/down direction.
+ # Same as `a[(-1..0).step(-1), ...]`.
+ def flipud
+ reverse(0)
+ end
+
+ # Multi-dimensional array indexing.
+ # Same as [] for one-dimensional NArray.
+ # Similar to numpy's tuple indexing, i.e., `a[[1,2,..],[3,4,..]]`
+ # (This method will be rewritten in C)
+ # @return [Numo::NArray] one-dimensional view of self.
+ # @example
+ # p x = Numo::DFloat.new(3,3,3).seq
+ # # Numo::DFloat#shape=[3,3,3]
+ # # [[[0, 1, 2],
+ # # [3, 4, 5],
+ # # [6, 7, 8]],
+ # # [[9, 10, 11],
+ # # [12, 13, 14],
+ # # [15, 16, 17]],
+ # # [[18, 19, 20],
+ # # [21, 22, 23],
+ # # [24, 25, 26]]]
+ #
+ # p x.at([0,1,2],[0,1,2],[-1,-2,-3])
+ # # Numo::DFloat(view)#shape=[3]
+ # # [2, 13, 24]
+ def at(*indices)
+ if indices.size != ndim
+ raise DimensionError, "argument length does not match dimension size"
+ end
+ idx = nil
+ stride = 1
+ (indices.size-1).downto(0) do |i|
+ ix = Int64.cast(indices[i])
+ if ix.ndim != 1
+ raise DimensionError, "index array is not one-dimensional"
+ end
+ ix[ix < 0] += shape[i]
+ if ((ix < 0) & (ix >= shape[i])).any?
+ raise IndexError, "index array is out of range"
+ end
+ if idx
+ if idx.size != ix.size
+ raise ShapeError, "index array sizes mismatch"
+ end
+ idx += ix * stride
+ stride *= shape[i]
+ else
+ idx = ix
+ stride = shape[i]
+ end
+ end
+ self[idx]
+ end
+
+ # Rotate in the plane specified by axes.
+ # @example
+ # p a = Numo::Int32.new(2,2).seq
+ # # Numo::Int32#shape=[2,2]
+ # # [[0, 1],
+ # # [2, 3]]
+ #
+ # p a.rot90
+ # # Numo::Int32(view)#shape=[2,2]
+ # # [[1, 3],
+ # # [0, 2]]
+ #
+ # p a.rot90(2)
+ # # Numo::Int32(view)#shape=[2,2]
+ # # [[3, 2],
+ # # [1, 0]]
+ #
+ # p a.rot90(3)
+ # # Numo::Int32(view)#shape=[2,2]
+ # # [[2, 0],
+ # # [3, 1]]
+ def rot90(k=1,axes=[0,1])
+ case k % 4
+ when 0
+ view
+ when 1
+ swapaxes(*axes).reverse(axes[0])
+ when 2
+ reverse(*axes)
+ when 3
+ swapaxes(*axes).reverse(axes[1])
+ end
+ end
+
+ def to_i
+ if size==1
+ self[0].to_i
+ else
+ # convert to Int?
+ raise TypeError, "can't convert #{self.class} into Integer"
+ end
+ end
+
+ def to_f
+ if size==1
+ self[0].to_f
+ else
+ # convert to DFloat?
+ raise TypeError, "can't convert #{self.class} into Float"
+ end
+ end
+
+ def to_c
+ if size==1
+ Complex(self[0])
+ else
+ # convert to DComplex?
+ raise TypeError, "can't convert #{self.class} into Complex"
+ end
+ end
+
+ # Convert the argument to an narray if not an narray.
+ def self.cast(a)
+ a.kind_of?(NArray) ? a : NArray.array_type(a).cast(a)
+ end
+
+ def self.asarray(a)
+ case a
+ when NArray
+ (a.ndim == 0) ? a[:new] : a
+ when Numeric,Range
+ self[a]
+ else
+ cast(a)
+ end
+ end
+
+ # parse matrix like matlab, octave
+ # @example
+ # a = Numo::DFloat.parse %[
+ # 2 -3 5
+ # 4 9 7
+ # 2 -1 6
+ # ]
+ # => Numo::DFloat#shape=[3,3]
+ # [[2, -3, 5],
+ # [4, 9, 7],
+ # [2, -1, 6]]
+
+ def self.parse(str, split1d:/\s+/, split2d:/;?$|;/,
+ split3d:/\s*\n(\s*\n)+/m)
+ a = []
+ str.split(split3d).each do |block|
+ b = []
+ #print "b"; p block
+ block.split(split2d).each do |line|
+ #p line
+ line.strip!
+ if !line.empty?
+ c = []
+ line.split(split1d).each do |item|
+ c << eval(item.strip) if !item.empty?
+ end
+ b << c if !c.empty?
+ end
+ end
+ a << b if !b.empty?
+ end
+ if a.size==1
+ self.cast(a[0])
+ else
+ self.cast(a)
+ end
+ end
+
+ # Append values to the end of an narray.
+ # @example
+ # a = Numo::DFloat[1, 2, 3]
+ # p a.append([[4, 5, 6], [7, 8, 9]])
+ # # Numo::DFloat#shape=[9]
+ # # [1, 2, 3, 4, 5, 6, 7, 8, 9]
+ #
+ # a = Numo::DFloat[[1, 2, 3]]
+ # p a.append([[4, 5, 6], [7, 8, 9]],axis:0)
+ # # Numo::DFloat#shape=[3,3]
+ # # [[1, 2, 3],
+ # # [4, 5, 6],
+ # # [7, 8, 9]]
+ #
+ # a = Numo::DFloat[[1, 2, 3], [4, 5, 6]]
+ # p a.append([7, 8, 9], axis:0)
+ # # in `append': dimension mismatch (Numo::NArray::DimensionError)
+
+ def append(other,axis:nil)
+ other = self.class.cast(other)
+ if axis
+ if ndim != other.ndim
+ raise DimensionError, "dimension mismatch"
+ end
+ return concatenate(other,axis:axis)
+ else
+ a = self.class.zeros(size+other.size)
+ a[0...size] = self[true]
+ a[size..-1] = other[true]
+ return a
+ end
+ end
+
+ # Return a new array with sub-arrays along an axis deleted.
+ # If axis is not given, obj is applied to the flattened array.
+
+ # @example
+ # a = Numo::DFloat[[1,2,3,4], [5,6,7,8], [9,10,11,12]]
+ # p a.delete(1,0)
+ # # Numo::DFloat(view)#shape=[2,4]
+ # # [[1, 2, 3, 4],
+ # # [9, 10, 11, 12]]
+ #
+ # p a.delete((0..-1).step(2),1)
+ # # Numo::DFloat(view)#shape=[3,2]
+ # # [[2, 4],
+ # # [6, 8],
+ # # [10, 12]]
+ #
+ # p a.delete([1,3,5])
+ # # Numo::DFloat(view)#shape=[9]
+ # # [1, 3, 5, 7, 8, 9, 10, 11, 12]
+
+ def delete(indice,axis=nil)
+ if axis
+ bit = Bit.ones(shape[axis])
+ bit[indice] = 0
+ idx = [true]*ndim
+ idx[axis] = bit.where
+ return self[*idx].copy
+ else
+ bit = Bit.ones(size)
+ bit[indice] = 0
+ return self[bit.where].copy
+ end
+ end
+
+ # Insert values along the axis before the indices.
+ # @example
+ # p a = Numo::DFloat[[1, 2], [3, 4]]
+ # a = Numo::Int32[[1, 1], [2, 2], [3, 3]]
+ #
+ # p a.insert(1,5)
+ # # Numo::Int32#shape=[7]
+ # # [1, 5, 1, 2, 2, 3, 3]
+ #
+ # p a.insert(1, 5, axis:1)
+ # # Numo::Int32#shape=[3,3]
+ # # [[1, 5, 1],
+ # # [2, 5, 2],
+ # # [3, 5, 3]]
+ #
+ # p a.insert([1], [[11],[12],[13]], axis:1)
+ # # Numo::Int32#shape=[3,3]
+ # # [[1, 11, 1],
+ # # [2, 12, 2],
+ # # [3, 13, 3]]
+ #
+ # p a.insert(1, [11, 12, 13], axis:1)
+ # # Numo::Int32#shape=[3,3]
+ # # [[1, 11, 1],
+ # # [2, 12, 2],
+ # # [3, 13, 3]]
+ #
+ # p a.insert([1], [11, 12, 13], axis:1)
+ # # Numo::Int32#shape=[3,5]
+ # # [[1, 11, 12, 13, 1],
+ # # [2, 11, 12, 13, 2],
+ # # [3, 11, 12, 13, 3]]
+ #
+ # p b = a.flatten
+ # # Numo::Int32(view)#shape=[6]
+ # # [1, 1, 2, 2, 3, 3]
+ #
+ # p b.insert(2,[15,16])
+ # # Numo::Int32#shape=[8]
+ # # [1, 1, 15, 16, 2, 2, 3, 3]
+ #
+ # p b.insert([2,2],[15,16])
+ # # Numo::Int32#shape=[8]
+ # # [1, 1, 15, 16, 2, 2, 3, 3]
+ #
+ # p b.insert([2,1],[15,16])
+ # # Numo::Int32#shape=[8]
+ # # [1, 16, 1, 15, 2, 2, 3, 3]
+ #
+ # p b.insert([2,0,1],[15,16,17])
+ # # Numo::Int32#shape=[9]
+ # # [16, 1, 17, 1, 15, 2, 2, 3, 3]
+ #
+ # p b.insert(2..3, [15, 16])
+ # # Numo::Int32#shape=[8]
+ # # [1, 1, 15, 2, 16, 2, 3, 3]
+ #
+ # p b.insert(2, [7.13, 0.5])
+ # # Numo::Int32#shape=[8]
+ # # [1, 1, 7, 0, 2, 2, 3, 3]
+ #
+ # p x = Numo::DFloat.new(2,4).seq
+ # # Numo::DFloat#shape=[2,4]
+ # # [[0, 1, 2, 3],
+ # # [4, 5, 6, 7]]
+ #
+ # p x.insert([1,3],999,axis:1)
+ # # Numo::DFloat#shape=[2,6]
+ # # [[0, 999, 1, 2, 999, 3],
+ # # [4, 999, 5, 6, 999, 7]]
+
+ def insert(indice,values,axis:nil)
+ if axis
+ values = self.class.asarray(values)
+ nd = values.ndim
+ midx = [:new]*(ndim-nd) + [true]*nd
+ case indice
+ when Numeric
+ midx[-nd-1] = true
+ midx[axis] = :new
+ end
+ values = values[*midx]
+ else
+ values = self.class.asarray(values).flatten
+ end
+ idx = Int64.asarray(indice)
+ nidx = idx.size
+ if nidx == 1
+ nidx = values.shape[axis||0]
+ idx = idx + Int64.new(nidx).seq
+ else
+ sidx = idx.sort_index
+ idx[sidx] += Int64.new(nidx).seq
+ end
+ if axis
+ bit = Bit.ones(shape[axis]+nidx)
+ bit[idx] = 0
+ new_shape = shape
+ new_shape[axis] += nidx
+ a = self.class.zeros(new_shape)
+ mdidx = [true]*ndim
+ mdidx[axis] = bit.where
+ a[*mdidx] = self
+ mdidx[axis] = idx
+ a[*mdidx] = values
+ else
+ bit = Bit.ones(size+nidx)
+ bit[idx] = 0
+ a = self.class.zeros(size+nidx)
+ a[bit.where] = self.flatten
+ a[idx] = values
+ end
+ return a
+ end
+
+ class << self
+ # @example
+ # p a = Numo::DFloat[[1, 2], [3, 4]]
+ # # Numo::DFloat#shape=[2,2]
+ # # [[1, 2],
+ # # [3, 4]]
+ #
+ # p b = Numo::DFloat[[5, 6]]
+ # # Numo::DFloat#shape=[1,2]
+ # # [[5, 6]]
+ #
+ # p Numo::NArray.concatenate([a,b],axis:0)
+ # # Numo::DFloat#shape=[3,2]
+ # # [[1, 2],
+ # # [3, 4],
+ # # [5, 6]]
+ #
+ # p Numo::NArray.concatenate([a,b.transpose], axis:1)
+ # # Numo::DFloat#shape=[2,3]
+ # # [[1, 2, 5],
+ # # [3, 4, 6]]
+
+ def concatenate(arrays,axis:0)
+ klass = (self==NArray) ? NArray.array_type(arrays) : self
+ nd = 0
+ arrays = arrays.map do |a|
+ case a
+ when NArray
+ # ok
+ when Numeric
+ a = klass[a]
+ when Array
+ a = klass.cast(a)
+ else
+ raise TypeError,"not Numo::NArray: #{a.inspect[0..48]}"
+ end
+ if a.ndim > nd
+ nd = a.ndim
+ end
+ a
+ end
+ if axis < 0
+ axis += nd
+ end
+ if axis < 0 || axis >= nd
+ raise ArgumentError,"axis is out of range"
+ end
+ new_shape = nil
+ sum_size = 0
+ arrays.each do |a|
+ a_shape = a.shape
+ if nd != a_shape.size
+ a_shape = [1]*(nd-a_shape.size) + a_shape
+ end
+ sum_size += a_shape.delete_at(axis)
+ if new_shape
+ if new_shape != a_shape
+ raise ShapeError,"shape mismatch"
+ end
+ else
+ new_shape = a_shape
+ end
+ end
+ new_shape.insert(axis,sum_size)
+ result = klass.zeros(*new_shape)
+ lst = 0
+ refs = [true] * nd
+ arrays.each do |a|
+ fst = lst
+ lst = fst + (a.shape[axis-nd]||1)
+ refs[axis] = fst...lst
+ result[*refs] = a
+ end
+ result
+ end
+
+ # Stack arrays vertically (row wise).
+ # @example
+ # a = Numo::Int32[1,2,3]
+ # b = Numo::Int32[2,3,4]
+ # p Numo::NArray.vstack([a,b])
+ # # Numo::Int32#shape=[2,3]
+ # # [[1, 2, 3],
+ # # [2, 3, 4]]
+ #
+ # a = Numo::Int32[[1],[2],[3]]
+ # b = Numo::Int32[[2],[3],[4]]
+ # p Numo::NArray.vstack([a,b])
+ # # Numo::Int32#shape=[6,1]
+ # # [[1],
+ # # [2],
+ # # [3],
+ # # [2],
+ # # [3],
+ # # [4]]
+
+ def vstack(arrays)
+ arys = arrays.map do |a|
+ _atleast_2d(cast(a))
+ end
+ concatenate(arys,axis:0)
+ end
+
+ # Stack arrays horizontally (column wise).
+ # @example
+ # a = Numo::Int32[1,2,3]
+ # b = Numo::Int32[2,3,4]
+ # p Numo::NArray.hstack([a,b])
+ # # Numo::Int32#shape=[6]
+ # # [1, 2, 3, 2, 3, 4]
+ #
+ # a = Numo::Int32[[1],[2],[3]]
+ # b = Numo::Int32[[2],[3],[4]]
+ # p Numo::NArray.hstack([a,b])
+ # # Numo::Int32#shape=[3,2]
+ # # [[1, 2],
+ # # [2, 3],
+ # # [3, 4]]
+
+ def hstack(arrays)
+ klass = (self==NArray) ? NArray.array_type(arrays) : self
+ nd = 0
+ arys = arrays.map do |a|
+ a = klass.cast(a)
+ nd = a.ndim if a.ndim > nd
+ a
+ end
+ dim = (nd >= 2) ? 1 : 0
+ concatenate(arys,axis:dim)
+ end
+
+ # Stack arrays in depth wise (along third axis).
+ # @example
+ # a = Numo::Int32[1,2,3]
+ # b = Numo::Int32[2,3,4]
+ # p Numo::NArray.dstack([a,b])
+ # # Numo::Int32#shape=[1,3,2]
+ # # [[[1, 2],
+ # # [2, 3],
+ # # [3, 4]]]
+ #
+ # a = Numo::Int32[[1],[2],[3]]
+ # b = Numo::Int32[[2],[3],[4]]
+ # p Numo::NArray.dstack([a,b])
+ # # Numo::Int32#shape=[3,1,2]
+ # # [[[1, 2]],
+ # # [[2, 3]],
+ # # [[3, 4]]]
+
+ def dstack(arrays)
+ arys = arrays.map do |a|
+ _atleast_3d(cast(a))
+ end
+ concatenate(arys,axis:2)
+ end
+
+ # Stack 1-d arrays into columns of a 2-d array.
+ # @example
+ # x = Numo::Int32[1,2,3]
+ # y = Numo::Int32[2,3,4]
+ # p Numo::NArray.column_stack([x,y])
+ # # Numo::Int32#shape=[3,2]
+ # # [[1, 2],
+ # # [2, 3],
+ # # [3, 4]]
+
+ def column_stack(arrays)
+ arys = arrays.map do |a|
+ a = cast(a)
+ case a.ndim
+ when 0; a[:new,:new]
+ when 1; a[true,:new]
+ else; a
+ end
+ end
+ concatenate(arys,axis:1)
+ end
+
+ private
+ # Return an narray with at least two dimension.
+ def _atleast_2d(a)
+ case a.ndim
+ when 0; a[:new,:new]
+ when 1; a[:new,true]
+ else; a
+ end
+ end
+
+ # Return an narray with at least three dimension.
+ def _atleast_3d(a)
+ case a.ndim
+ when 0; a[:new,:new,:new]
+ when 1; a[:new,true,:new]
+ when 2; a[true,true,:new]
+ else; a
+ end
+ end
+
+ end # class << self
+
+ # @example
+ # p a = Numo::DFloat[[1, 2], [3, 4]]
+ # # Numo::DFloat#shape=[2,2]
+ # # [[1, 2],
+ # # [3, 4]]
+ #
+ # p b = Numo::DFloat[[5, 6]]
+ # # Numo::DFloat#shape=[1,2]
+ # # [[5, 6]]
+ #
+ # p a.concatenate(b,axis:0)
+ # # Numo::DFloat#shape=[3,2]
+ # # [[1, 2],
+ # # [3, 4],
+ # # [5, 6]]
+ #
+ # p a.concatenate(b.transpose, axis:1)
+ # # Numo::DFloat#shape=[2,3]
+ # # [[1, 2, 5],
+ # # [3, 4, 6]]
+
+ def concatenate(*arrays,axis:0)
+ axis = check_axis(axis)
+ self_shape = shape
+ self_shape.delete_at(axis)
+ sum_size = shape[axis]
+ arrays.map! do |a|
+ case a
+ when NArray
+ # ok
+ when Numeric
+ a = self.class.new(1).store(a)
+ when Array
+ a = self.class.cast(a)
+ else
+ raise TypeError,"not Numo::NArray: #{a.inspect[0..48]}"
+ end
+ if a.ndim > ndim
+ raise ShapeError,"dimension mismatch"
+ end
+ a_shape = a.shape
+ sum_size += a_shape.delete_at(axis-ndim) || 1
+ if self_shape != a_shape
+ raise ShapeError,"shape mismatch"
+ end
+ a
+ end
+ self_shape.insert(axis,sum_size)
+ result = self.class.zeros(*self_shape)
+ lst = shape[axis]
+ refs = [true] * ndim
+ refs[axis] = 0...lst
+ result[*refs] = self
+ arrays.each do |a|
+ fst = lst
+ lst = fst + (a.shape[axis-ndim] || 1)
+ refs[axis] = fst...lst
+ result[*refs] = a
+ end
+ result
+ end
+
+ # @example
+ # p x = Numo::DFloat.new(9).seq
+ # # Numo::DFloat#shape=[9]
+ # # [0, 1, 2, 3, 4, 5, 6, 7, 8]
+ #
+ # pp x.split(3)
+ # # [Numo::DFloat(view)#shape=[3]
+ # # [0, 1, 2],
+ # # Numo::DFloat(view)#shape=[3]
+ # # [3, 4, 5],
+ # # Numo::DFloat(view)#shape=[3]
+ # # [6, 7, 8]]
+ #
+ # p x = Numo::DFloat.new(8).seq
+ # # Numo::DFloat#shape=[8]
+ # # [0, 1, 2, 3, 4, 5, 6, 7]
+ #
+ # pp x.split([3, 5, 6, 10])
+ # # [Numo::DFloat(view)#shape=[3]
+ # # [0, 1, 2],
+ # # Numo::DFloat(view)#shape=[2]
+ # # [3, 4],
+ # # Numo::DFloat(view)#shape=[1]
+ # # [5],
+ # # Numo::DFloat(view)#shape=[2]
+ # # [6, 7],
+ # # Numo::DFloat(view)#shape=[0][]]
+
+ def split(indices_or_sections, axis:0)
+ axis = check_axis(axis)
+ size_axis = shape[axis]
+ case indices_or_sections
+ when Integer
+ div_axis, mod_axis = size_axis.divmod(indices_or_sections)
+ refs = [true]*ndim
+ beg_idx = 0
+ mod_axis.times.map do |i|
+ end_idx = beg_idx + div_axis + 1
+ refs[axis] = beg_idx ... end_idx
+ beg_idx = end_idx
+ self[*refs]
+ end +
+ (indices_or_sections-mod_axis).times.map do |i|
+ end_idx = beg_idx + div_axis
+ refs[axis] = beg_idx ... end_idx
+ beg_idx = end_idx
+ self[*refs]
+ end
+ when NArray
+ split(indices_or_sections.to_a,axis:axis)
+ when Array
+ refs = [true]*ndim
+ fst = 0
+ (indices_or_sections + [size_axis]).map do |lst|
+ lst = size_axis if lst > size_axis
+ refs[axis] = (fst < size_axis) ? fst...lst : -1...-1
+ fst = lst
+ self[*refs]
+ end
+ else
+ raise TypeError,"argument must be Integer or Array"
+ end
+ end
+
+ # @example
+ # p x = Numo::DFloat.new(4,4).seq
+ # # Numo::DFloat#shape=[4,4]
+ # # [[0, 1, 2, 3],
+ # # [4, 5, 6, 7],
+ # # [8, 9, 10, 11],
+ # # [12, 13, 14, 15]]
+ #
+ # pp x.hsplit(2)
+ # # [Numo::DFloat(view)#shape=[4,2]
+ # # [[0, 1],
+ # # [4, 5],
+ # # [8, 9],
+ # # [12, 13]],
+ # # Numo::DFloat(view)#shape=[4,2]
+ # # [[2, 3],
+ # # [6, 7],
+ # # [10, 11],
+ # # [14, 15]]]
+ #
+ # pp x.hsplit([3, 6])
+ # # [Numo::DFloat(view)#shape=[4,3]
+ # # [[0, 1, 2],
+ # # [4, 5, 6],
+ # # [8, 9, 10],
+ # # [12, 13, 14]],
+ # # Numo::DFloat(view)#shape=[4,1]
+ # # [[3],
+ # # [7],
+ # # [11],
+ # # [15]],
+ # # Numo::DFloat(view)#shape=[4,0][]]
+
+ def vsplit(indices_or_sections)
+ split(indices_or_sections, axis:0)
+ end
+
+ def hsplit(indices_or_sections)
+ split(indices_or_sections, axis:1)
+ end
+
+ def dsplit(indices_or_sections)
+ split(indices_or_sections, axis:2)
+ end
+
+ # @example
+ # p a = Numo::NArray[0,1,2]
+ # # Numo::Int32#shape=[3]
+ # # [0, 1, 2]
+ #
+ # p a.tile(2)
+ # # Numo::Int32#shape=[6]
+ # # [0, 1, 2, 0, 1, 2]
+ #
+ # p a.tile(2,2)
+ # # Numo::Int32#shape=[2,6]
+ # # [[0, 1, 2, 0, 1, 2],
+ # # [0, 1, 2, 0, 1, 2]]
+ #
+ # p a.tile(2,1,2)
+ # # Numo::Int32#shape=[2,1,6]
+ # # [[[0, 1, 2, 0, 1, 2]],
+ # # [[0, 1, 2, 0, 1, 2]]]
+ #
+ # p b = Numo::NArray[[1, 2], [3, 4]]
+ # # Numo::Int32#shape=[2,2]
+ # # [[1, 2],
+ # # [3, 4]]
+ #
+ # p b.tile(2)
+ # # Numo::Int32#shape=[2,4]
+ # # [[1, 2, 1, 2],
+ # # [3, 4, 3, 4]]
+ #
+ # p b.tile(2,1)
+ # # Numo::Int32#shape=[4,2]
+ # # [[1, 2],
+ # # [3, 4],
+ # # [1, 2],
+ # # [3, 4]]
+ #
+ # p c = Numo::NArray[1,2,3,4]
+ # # Numo::Int32#shape=[4]
+ # # [1, 2, 3, 4]
+ #
+ # p c.tile(4,1)
+ # # Numo::Int32#shape=[4,4]
+ # # [[1, 2, 3, 4],
+ # # [1, 2, 3, 4],
+ # # [1, 2, 3, 4],
+ # # [1, 2, 3, 4]]
+
+ def tile(*arg)
+ arg.each do |i|
+ if !i.kind_of?(Integer) || i<1
+ raise ArgumentError,"argument should be positive integer"
+ end
+ end
+ ns = arg.size
+ nd = self.ndim
+ shp = self.shape
+ new_shp = []
+ src_shp = []
+ res_shp = []
+ (nd-ns).times do
+ new_shp << 1
+ new_shp << (n = shp.shift)
+ src_shp << :new
+ src_shp << true
+ res_shp << n
+ end
+ (ns-nd).times do
+ new_shp << (m = arg.shift)
+ new_shp << 1
+ src_shp << :new
+ src_shp << :new
+ res_shp << m
+ end
+ [nd,ns].min.times do
+ new_shp << (m = arg.shift)
+ new_shp << (n = shp.shift)
+ src_shp << :new
+ src_shp << true
+ res_shp << n*m
+ end
+ self.class.new(*new_shp).store(self[*src_shp]).reshape(*res_shp)
+ end
+
+ # @example
+ # p Numo::NArray[3].repeat(4)
+ # # Numo::Int32#shape=[4]
+ # # [3, 3, 3, 3]
+ #
+ # p x = Numo::NArray[[1,2],[3,4]]
+ # # Numo::Int32#shape=[2,2]
+ # # [[1, 2],
+ # # [3, 4]]
+ #
+ # p x.repeat(2)
+ # # Numo::Int32#shape=[8]
+ # # [1, 1, 2, 2, 3, 3, 4, 4]
+ #
+ # p x.repeat(3,axis:1)
+ # # Numo::Int32#shape=[2,6]
+ # # [[1, 1, 1, 2, 2, 2],
+ # # [3, 3, 3, 4, 4, 4]]
+ #
+ # p x.repeat([1,2],axis:0)
+ # # Numo::Int32#shape=[3,2]
+ # # [[1, 2],
+ # # [3, 4],
+ # # [3, 4]]
+
+ def repeat(arg,axis:nil)
+ case axis
+ when Integer
+ axis = check_axis(axis)
+ c = self
+ when NilClass
+ c = self.flatten
+ axis = 0
+ else
+ raise ArgumentError,"invalid axis"
+ end
+ case arg
+ when Integer
+ if !arg.kind_of?(Integer) || arg<1
+ raise ArgumentError,"argument should be positive integer"
+ end
+ idx = c.shape[axis].times.map{|i| [i]*arg}.flatten
+ else
+ arg = arg.to_a
+ if arg.size != c.shape[axis]
+ raise ArgumentError,"repeat size shoud be equal to size along axis"
+ end
+ arg.each do |i|
+ if !i.kind_of?(Integer) || i<0
+ raise ArgumentError,"argument should be non-negative integer"
+ end
+ end
+ idx = arg.each_with_index.map{|a,i| [i]*a}.flatten
+ end
+ ref = [true] * c.ndim
+ ref[axis] = idx
+ c[*ref].copy
+ end
+
+ # Calculate the n-th discrete difference along given axis.
+ # @example
+ # p x = Numo::DFloat[1, 2, 4, 7, 0]
+ # # Numo::DFloat#shape=[5]
+ # # [1, 2, 4, 7, 0]
+ #
+ # p x.diff
+ # # Numo::DFloat#shape=[4]
+ # # [1, 2, 3, -7]
+ #
+ # p x.diff(2)
+ # # Numo::DFloat#shape=[3]
+ # # [1, 1, -10]
+ #
+ # p x = Numo::DFloat[[1, 3, 6, 10], [0, 5, 6, 8]]
+ # # Numo::DFloat#shape=[2,4]
+ # # [[1, 3, 6, 10],
+ # # [0, 5, 6, 8]]
+ #
+ # p x.diff
+ # # Numo::DFloat#shape=[2,3]
+ # # [[2, 3, 4],
+ # # [5, 1, 2]]
+ #
+ # p x.diff(axis:0)
+ # # Numo::DFloat#shape=[1,4]
+ # # [[-1, 2, 0, -2]]
+
+ def diff(n=1,axis:-1)
+ axis = check_axis(axis)
+ if n < 0 || n >= shape[axis]
+ raise ShapeError,"n=#{n} is invalid for shape[#{axis}]=#{shape[axis]}"
+ end
+ # calculate polynomial coefficient
+ c = self.class[-1,1]
+ 2.upto(n) do |i|
+ x = self.class.zeros(i+1)
+ x[0..-2] = c
+ y = self.class.zeros(i+1)
+ y[1..-1] = c
+ c = y - x
+ end
+ s = [true]*ndim
+ s[axis] = n..-1
+ result = self[*s].dup
+ sum = result.inplace
+ (n-1).downto(0) do |i|
+ s = [true]*ndim
+ s[axis] = i..-n-1+i
+ sum + self[*s] * c[i] # inplace addition
+ end
+ return result
+ end
+
+
+ # Upper triangular matrix.
+ # Return a copy with the elements below the k-th diagonal filled with zero.
+ def triu(k=0)
+ dup.triu!(k)
+ end
+
+ # Upper triangular matrix.
+ # Fill the self elements below the k-th diagonal with zero.
+ def triu!(k=0)
+ if ndim < 2
+ raise NArray::ShapeError, "must be >= 2-dimensional array"
+ end
+ if contiguous?
+ *shp,m,n = shape
+ idx = tril_indices(k-1)
+ reshape!(*shp,m*n)
+ self[false,idx] = 0
+ reshape!(*shp,m,n)
+ else
+ store(triu(k))
+ end
+ end
+
+ # Return the indices for the uppler-triangle on and above the k-th diagonal.
+ def triu_indices(k=0)
+ if ndim < 2
+ raise NArray::ShapeError, "must be >= 2-dimensional array"
+ end
+ m,n = shape[-2..-1]
+ NArray.triu_indices(m,n,k=0)
+ end
+
+ # Return the indices for the uppler-triangle on and above the k-th diagonal.
+ def self.triu_indices(m,n,k=0)
+ x = Numo::Int64.new(m,1).seq + k
+ y = Numo::Int64.new(1,n).seq
+ (x<=y).where
+ end
+
+ # Lower triangular matrix.
+ # Return a copy with the elements above the k-th diagonal filled with zero.
+ def tril(k=0)
+ dup.tril!(k)
+ end
+
+ # Lower triangular matrix.
+ # Fill the self elements above the k-th diagonal with zero.
+ def tril!(k=0)
+ if ndim < 2
+ raise NArray::ShapeError, "must be >= 2-dimensional array"
+ end
+ if contiguous?
+ idx = triu_indices(k+1)
+ *shp,m,n = shape
+ reshape!(*shp,m*n)
+ self[false,idx] = 0
+ reshape!(*shp,m,n)
+ else
+ store(tril(k))
+ end
+ end
+
+ # Return the indices for the lower-triangle on and below the k-th diagonal.
+ def tril_indices(k=0)
+ if ndim < 2
+ raise NArray::ShapeError, "must be >= 2-dimensional array"
+ end
+ m,n = shape[-2..-1]
+ NArray.tril_indices(m,n,k)
+ end
+
+ # Return the indices for the lower-triangle on and below the k-th diagonal.
+ def self.tril_indices(m,n,k=0)
+ x = Numo::Int64.new(m,1).seq + k
+ y = Numo::Int64.new(1,n).seq
+ (x>=y).where
+ end
+
+ # Return the k-th diagonal indices.
+ def diag_indices(k=0)
+ if ndim < 2
+ raise NArray::ShapeError, "must be >= 2-dimensional array"
+ end
+ m,n = shape[-2..-1]
+ NArray.diag_indices(m,n,k)
+ end
+
+ # Return the k-th diagonal indices.
+ def self.diag_indices(m,n,k=0)
+ x = Numo::Int64.new(m,1).seq + k
+ y = Numo::Int64.new(1,n).seq
+ (x.eq y).where
+ end
+
+ # Return a matrix whose diagonal is constructed by self along the last axis.
+ def diag(k=0)
+ *shp,n = shape
+ n += k.abs
+ a = self.class.zeros(*shp,n,n)
+ a.diagonal(k).store(self)
+ a
+ end
+
+ # Return the sum along diagonals of the array.
+ #
+ # If 2-D array, computes the summation along its diagonal with the
+ # given offset, i.e., sum of `a[i,i+offset]`.
+ # If more than 2-D array, the diagonal is determined from the axes
+ # specified by axis argument. The default is axis=[-2,-1].
+ # @param offset [Integer] (optional, default=0) diagonal offset
+ # @param axis [Array] (optional, default=[-2,-1]) diagonal axis
+ # @param nan [Bool] (optional, default=false) nan-aware algorithm, i.e., if true then it ignores nan.
+
+ def trace(offset=nil,axis=nil,nan:false)
+ diagonal(offset,axis).sum(nan:nan,axis:-1)
+ end
+
+
+ @@warn_slow_dot = false
+
+ # Dot product of two arrays.
+ # @param b [Numo::NArray]
+ # @return [Numo::NArray] return dot product
+
+ def dot(b)
+ t = self.class::UPCAST[b.class]
+ if defined?(Linalg) && [SFloat,DFloat,SComplex,DComplex].include?(t)
+ Linalg.dot(self,b)
+ else
+ b = self.class.asarray(b)
+ case b.ndim
+ when 1
+ mulsum(b, axis:-1)
+ else
+ case ndim
+ when 0
+ b.mulsum(self, axis:-2)
+ when 1
+ self[true,:new].mulsum(b, axis:-2)
+ else
+ unless @@warn_slow_dot
+ nx = 200
+ ns = 200000
+ am,an = shape[-2..-1]
+ bm,bn = b.shape[-2..-1]
+ if am > nx && an > nx && bm > nx && bn > nx &&
+ size > ns && b.size > ns
+ @@warn_slow_dot = true
+ warn "\nwarning: Built-in matrix dot is slow. Consider installing Numo::Linalg.\n\n"
+ end
+ end
+ self[false,:new].mulsum(b[false,:new,true,true], axis:-2)
+ end
+ end
+ end
+ end
+
+ # Inner product of two arrays.
+ # Same as `(a*b).sum(axis:-1)`.
+ # @param b [Numo::NArray]
+ # @param axis [Integer] applied axis
+ # @return [Numo::NArray] return (a*b).sum(axis:axis)
+
+ def inner(b, axis:-1)
+ mulsum(b, axis:axis)
+ end
+
+ # Outer product of two arrays.
+ # Same as `self[false,:new] * b[false,:new,true]`.
+ #
+ # @param b [Numo::NArray]
+ # @param axis [Integer] applied axis (default=-1)
+ # @return [Numo::NArray] return outer product
+ # @example
+ # a = Numo::DFloat.ones(5)
+ # => Numo::DFloat#shape=[5]
+ # [1, 1, 1, 1, 1]
+ # b = Numo::DFloat.linspace(-2,2,5)
+ # => Numo::DFloat#shape=[5]
+ # [-2, -1, 0, 1, 2]
+ # a.outer(b)
+ # => Numo::DFloat#shape=[5,5]
+ # [[-2, -1, 0, 1, 2],
+ # [-2, -1, 0, 1, 2],
+ # [-2, -1, 0, 1, 2],
+ # [-2, -1, 0, 1, 2],
+ # [-2, -1, 0, 1, 2]]
+
+ def outer(b, axis:nil)
+ b = NArray.cast(b)
+ if axis.nil?
+ self[false,:new] * ((b.ndim==0) ? b : b[false,:new,true])
+ else
+ md,nd = [ndim,b.ndim].minmax
+ axis = check_axis(axis) - nd
+ if axis < -md
+ raise ArgumentError,"axis=#{axis} is out of range"
+ end
+ adim = [true]*ndim
+ adim[axis+ndim+1,0] = :new
+ bdim = [true]*b.ndim
+ bdim[axis+b.ndim,0] = :new
+ self[*adim] * b[*bdim]
+ end
+ end
+
+ # Kronecker product of two arrays.
+ #
+ # kron(a,b)[k_0, k_1, ...] = a[i_0, i_1, ...] * b[j_0, j_1, ...]
+ # where: k_n = i_n * b.shape[n] + j_n
+ #
+ # @param b [Numo::NArray]
+ # @return [Numo::NArray] return Kronecker product
+ # @example
+ # Numo::DFloat[1,10,100].kron([5,6,7])
+ # => Numo::DFloat#shape=[9]
+ # [5, 6, 7, 50, 60, 70, 500, 600, 700]
+ # Numo::DFloat[5,6,7].kron([1,10,100])
+ # => Numo::DFloat#shape=[9]
+ # [5, 50, 500, 6, 60, 600, 7, 70, 700]
+ # Numo::DFloat.eye(2).kron(Numo::DFloat.ones(2,2))
+ # => Numo::DFloat#shape=[4,4]
+ # [[1, 1, 0, 0],
+ # [1, 1, 0, 0],
+ # [0, 0, 1, 1],
+ # [0, 0, 1, 1]]
+
+ def kron(b)
+ b = NArray.cast(b)
+ nda = ndim
+ ndb = b.ndim
+ shpa = shape
+ shpb = b.shape
+ adim = [:new]*(2*[ndb-nda,0].max) + [true,:new]*nda
+ bdim = [:new]*(2*[nda-ndb,0].max) + [:new,true]*ndb
+ shpr = (-[nda,ndb].max..-1).map{|i| (shpa[i]||1) * (shpb[i]||1)}
+ (self[*adim] * b[*bdim]).reshape(*shpr)
+ end
+
+
+ # under construction
+ def cov(y=nil, ddof:1, fweights:nil, aweights:nil)
+ if y
+ m = NArray.vstack([self,y])
+ else
+ m = self
+ end
+ w = nil
+ if fweights
+ f = fweights
+ w = f
+ end
+ if aweights
+ a = aweights
+ w = w ? w*a : a
+ end
+ if w
+ w_sum = w.sum(axis:-1, keepdims:true)
+ if ddof == 0
+ fact = w_sum
+ elsif aweights.nil?
+ fact = w_sum - ddof
+ else
+ wa_sum = (w*a).sum(axis:-1, keepdims:true)
+ fact = w_sum - ddof * wa_sum / w_sum
+ end
+ if (fact <= 0).any?
+ raise StandardError,"Degrees of freedom <= 0 for slice"
+ end
+ else
+ fact = m.shape[-1] - ddof
+ end
+ if w
+ m -= (m*w).sum(axis:-1, keepdims:true) / w_sum
+ mw = m*w
+ else
+ m -= m.mean(axis:-1, keepdims:true)
+ mw = m
+ end
+ mt = (m.ndim < 2) ? m : m.swapaxes(-2,-1)
+ mw.dot(mt.conj) / fact
+ end
+
+ private
+
+ # @!visibility private
+ def check_axis(axis)
+ unless Integer===axis
+ raise ArgumentError,"axis=#{axis} must be Integer"
+ end
+ a = axis
+ if a < 0
+ a += ndim
+ end
+ if a < 0 || a >= ndim
+ raise ArgumentError,"axis=#{axis} is invalid"
+ end
+ a
+ end
+
+ end
+end
diff --git a/numo-narray.gemspec b/numo-narray.gemspec
new file mode 100644
index 0000000..6357438
--- /dev/null
+++ b/numo-narray.gemspec
@@ -0,0 +1,36 @@
+# coding: utf-8
+lib = File.expand_path('../lib', __FILE__)
+$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
+
+open("ext/numo/narray/numo/narray.h") do |f|
+ f.each_line do |l|
+ if /NARRAY_VERSION "([\d.]+)"/ =~ l
+ NARRAY_VERSION = $1
+ break
+ end
+ end
+end
+
+Gem::Specification.new do |spec|
+ spec.name = "numo-narray"
+ spec.version = NARRAY_VERSION
+ spec.authors = ["Masahiro TANAKA"]
+ spec.email = ["masa16.tanaka at gmail.com"]
+ spec.description = %q{Numo::NArray - New NArray class library in Ruby/Numo.}
+ spec.summary = %q{alpha release of Numo::NArray - New NArray class library in Ruby/Numo (NUmerical MOdule)}
+ spec.homepage = "https://github.com/ruby-numo/narray"
+ spec.license = "BSD-3-Clause"
+ spec.required_ruby_version = '~> 2.1'
+
+ spec.files = `git ls-files Gemfile README.md Rakefile lib ext numo-narray.gemspec spec`.split($/)
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
+ spec.require_paths = ["lib"]
+ spec.extensions = ["ext/numo/narray/extconf.rb"]
+
+ spec.add_development_dependency "bundler", "~> 1.3"
+ spec.add_development_dependency "rake", "~> 0"
+ spec.add_development_dependency "rspec", "~> 3"
+ spec.add_development_dependency 'rake-compiler', "~> 1.0", ">= 1.0.1"
+ spec.add_development_dependency "rake-compiler-dock", "~> 0"
+end
diff --git a/spec/bit_spec.rb b/spec/bit_spec.rb
new file mode 100644
index 0000000..bc36863
--- /dev/null
+++ b/spec/bit_spec.rb
@@ -0,0 +1,93 @@
+require File.join(File.dirname(__FILE__), "../ext/numo/narray/narray")
+#Numo::NArray.debug = true
+
+RSpec.configure do |config|
+ config.filter_run :focus
+ config.run_all_when_everything_filtered = true
+end
+#context :focus=>true do ... end
+
+dtype = Numo::Bit
+
+describe dtype do
+ it{expect(dtype).to be < Numo::NArray}
+end
+
+procs = [
+ [proc{|tp,a| tp[*a] },""],
+ [proc{|tp,a| tp[*a][true] },"[true]"],
+ [proc{|tp,a| tp[*a][0..-1] },"[0..-1]"]
+]
+procs.each do |init,ref|
+
+ describe dtype,"[0,1,1,0,1,0,0,1]"+ref do
+ before(:all) do
+ @src = [0,1,1,0,1,0,0,1]
+ @n = @src.size
+ @a = init.call(dtype, at src)
+ end
+
+ it{expect(@a).to eq @src}
+ it{expect(@a & 0).to eq [0]*@n}
+ it{expect(@a & 1).to eq @src}
+ it{expect(@a | 0).to eq @src}
+ it{expect(@a | 1).to eq [1]*@n}
+ it{expect(@a ^ 0).to eq @src.map{|x| x^0}}
+ it{expect(@a ^ 1).to eq @src.map{|x| x^1}}
+ it{expect(~@a).to eq @src.map{|x| 1-x}}
+
+ it{expect(@a.count_true).to eq 4}
+ it{expect(@a.count_false).to eq 4}
+ it{expect(@a.where).to eq [1,2,4,7]}
+ it{expect(@a.where2).to eq [[1,2,4,7],[0,3,5,6]]}
+ it{expect(@a.mask(Numo::DFloat[1,2,3,4,5,6,7,8])).to eq [2,3,5,8]}
+ it{expect(@a).not_to be_all}
+ it{expect(@a).to be_any}
+ it{expect(@a).not_to be_none}
+
+ after(:all) do
+ @a = nil
+ end
+ end
+
+end
+
+procs = [
+ [proc{|tp,a| tp[*a] },""],
+ [proc{|tp,a| tp[*a][true,0..-1] },"[true,true]"],
+]
+procs.each do |init,ref|
+
+ describe dtype,"[[0,1,1,0],[1,0,0,1]]"+ref do
+ before(:all) do
+ @src = [[0,1,1,0],[1,0,0,1]]
+ @n = @src.size
+ @a = init.call(dtype, at src)
+ end
+
+ it{expect(@a[5]).to eq 0}
+ it{expect(@a[-1]).to eq 1}
+ it{expect(@a[1,0]).to eq @src[1][0]}
+ it{expect(@a[1,1]).to eq @src[1][1]}
+ it{expect(@a[1,2]).to eq @src[1][2]}
+ it{expect(@a[3..4]).to eq [0,1]}
+ it{expect(@a[0,1..2]).to eq [1,1]}
+ it{expect(@a[0,:*]).to eq @src[0]}
+ it{expect(@a[1,:*]).to eq @src[1]}
+ it{expect(@a[:*,1]).to eq [@src[0][1], at src[1][1]]}
+
+ it{expect(@a.count_true).to eq 4}
+ it{expect(@a.count_false).to eq 4}
+ it{expect(@a.where).to eq [1,2,4,7]}
+ it{expect(@a.where2).to eq [[1,2,4,7],[0,3,5,6]]}
+ it{expect(@a.mask(Numo::DFloat[[1,2,3,4],[5,6,7,8]])).to eq [2,3,5,8]}
+ it{expect(@a).not_to be_all}
+ it{expect(@a).to be_any}
+ it{expect(@a).not_to be_none}
+
+ after(:all) do
+ @a = nil
+ end
+ end
+
+end
diff --git a/spec/narray_spec.rb b/spec/narray_spec.rb
new file mode 100644
index 0000000..6fec60e
--- /dev/null
+++ b/spec/narray_spec.rb
@@ -0,0 +1,250 @@
+require File.join(File.dirname(__FILE__), "../ext/numo/narray/narray")
+#Numo::NArray.debug = true
+
+RSpec.configure do |config|
+ config.filter_run :focus
+ config.run_all_when_everything_filtered = true
+end
+#context :focus=>true do ... end
+
+types = [
+ Numo::DFloat,
+ Numo::SFloat,
+ Numo::DComplex,
+ Numo::SComplex,
+ Numo::Int64,
+ Numo::Int32,
+ Numo::Int16,
+ Numo::Int8,
+ Numo::UInt64,
+ Numo::UInt32,
+ Numo::UInt16,
+ Numo::UInt8,
+]
+#types = [Numo::DFloat]
+float_types = [
+ Numo::DFloat,
+ Numo::DComplex,
+]
+
+types.each do |dtype|
+
+ describe dtype do
+ it{expect(dtype).to be < Numo::NArray}
+ end
+
+ procs = [
+ [proc{|tp,a| tp[*a] },""],
+ [proc{|tp,a| tp[*a][true] },"[true]"],
+ [proc{|tp,a| tp[*a][0..-1] },"[0..-1]"]
+ ]
+ procs.each do |init,ref|
+
+ describe dtype,"[1,2,3,5,7,11]"+ref do
+ before(:all) do
+ @src = [1,2,3,5,7,11]
+ @a = init.call(dtype, at src)
+ end
+ #context :focus=>true do
+
+ it{expect(@a).to be_kind_of dtype}
+ it{expect(@a.size).to eq 6}
+ it{expect(@a.ndim).to eq 1}
+ it{expect(@a.shape).to eq [6]}
+ it{expect(@a).not_to be_inplace}
+ it{expect(@a).to be_row_major}
+ it{expect(@a).not_to be_column_major}
+ it{expect(@a).to be_host_order}
+ it{expect(@a).not_to be_byte_swapped}
+ it{expect(@a).to eq [1,2,3,5,7,11]}
+ it{expect(@a.to_a).to eq [1,2,3,5,7,11]}
+ it{expect(@a.to_a).to be_kind_of Array}
+ it{expect(@a.dup).to eq @a}
+ it{expect(@a.clone).to eq @a}
+ it{expect(@a.dup.object_id).not_to eq @a.object_id}
+ it{expect(@a.clone.object_id).not_to eq @a.object_id}
+
+ it{expect(@a.eq([1,1,3,3,7,7])).to eq [1,0,1,0,1,0]}
+ it{expect(@a[3..4]).to eq [5,7]}
+ it{expect(@a[5]).to eq 11}
+ it{expect(@a[-1]).to eq 11}
+ it{expect(@a[[4,3,0,1,5,2]]).to eq [7,5,1,2,11,3]}
+ it{expect(@a.sum).to eq 29}
+ if float_types.include?(dtype)
+ it{expect(@a.mean).to eq 29.0/6}
+ it{expect(@a.var).to eq 13.766666666666669}
+ it{expect(@a.stddev).to eq 3.710345895825168}
+ it{expect(@a.rms).to eq 5.901977069875258}
+ end
+ it{expect(@a.dup.fill(12)).to eq [12]*6}
+ it{expect((@a + 1)).to eq [2,3,4,6,8,12]}
+ it{expect((@a - 1)).to eq [0,1,2,4,6,10]}
+ it{expect((@a * 3)).to eq [3,6,9,15,21,33]}
+ it{expect((@a / 0.5)).to eq [2,4,6,10,14,22]}
+ it{expect((- at a)).to eq [-1,-2,-3,-5,-7,-11]}
+ it{expect((@a ** 2)).to eq [1,4,9,25,49,121]}
+ it{expect(@a.swap_byte.swap_byte).to eq [1,2,3,5,7,11]}
+ if dtype == Numo::DComplex || dtype == Numo::SComplex
+ it{expect(@a.real).to eq @src}
+ it{expect(@a.imag).to eq [0]*6}
+ it{expect(@a.conj).to eq @src}
+ it{expect(@a.angle).to eq [0]*6}
+ else
+ it{expect(@a.min).to eq 1}
+ it{expect(@a.max).to eq 11}
+ it{expect((@a >= 3)).to eq [0,0,1,1,1,1]}
+ it{expect((@a > 3)).to eq [0,0,0,1,1,1]}
+ it{expect((@a <= 3)).to eq [1,1,1,0,0,0]}
+ it{expect((@a < 3)).to eq [1,1,0,0,0,0]}
+ it{expect((@a.eq 3)).to eq [0,0,1,0,0,0]}
+ it{expect(@a.sort).to eq @src}
+ it{expect(@a.sort_index).to eq (0..5).to_a}
+ it{expect(@a.median).to eq 4}
+ end
+ end
+ end
+
+ describe dtype, '[1..4]' do
+ it{expect(dtype[1..4]).to eq [1,2,3,4]}
+ end
+
+ #describe dtype, ".seq(5)" do
+ # it do
+ # dtype.seq(5).should == [0,1,2,3,4]
+ # end
+ #end
+
+ procs2 = [
+ [proc{|tp,src| tp[*src] },""],
+ [proc{|tp,src| tp[*src][true,true] },"[true,true]"],
+ [proc{|tp,src| tp[*src][0..-1,0..-1] },"[0..-1,0..-1]"]
+ ]
+ procs2.each do |init,ref|
+
+ describe dtype,'[[1,2,3],[5,7,11]]'+ref do
+ before(:all) do
+ @src = [[1,2,3],[5,7,11]]
+ @a = init.call(dtype, at src)
+ end
+ #context :focus=>true do
+
+ it{expect(@a).to be_kind_of dtype}
+ it{expect(@a.size).to eq 6}
+ it{expect(@a.ndim).to eq 2}
+ it{expect(@a.shape).to eq [2,3]}
+ it{expect(@a).not_to be_inplace}
+ it{expect(@a).to be_row_major}
+ it{expect(@a).not_to be_column_major}
+ it{expect(@a).to be_host_order}
+ it{expect(@a).not_to be_byte_swapped}
+ it{expect(@a).to eq @src}
+ it{expect(@a.to_a).to eq @src}
+ it{expect(@a.to_a).to be_kind_of Array}
+
+ it{expect(@a.eq([[1,1,3],[3,7,7]])).to eq [[1,0,1],[0,1,0]]}
+ it{expect(@a[5]).to eq 11}
+ it{expect(@a[-1]).to eq 11}
+ it{expect(@a[1,0]).to eq @src[1][0]}
+ it{expect(@a[1,1]).to eq @src[1][1]}
+ it{expect(@a[1,2]).to eq @src[1][2]}
+ it{expect(@a[3..4]).to eq [5,7]}
+ it{expect(@a[0,1..2]).to eq [2,3]}
+ it{expect(@a[0,:*]).to eq @src[0]}
+ it{expect(@a[1,:*]).to eq @src[1]}
+ it{expect(@a[:*,1]).to eq [@src[0][1], at src[1][1]]}
+ it{expect(@a[true,[2,0,1]]).to eq [[3,1,2],[11,5,7]]}
+ it{expect(@a.reshape(3,2)).to eq [[1,2],[3,5],[7,11]]}
+ it{expect(@a.reshape(3,nil)).to eq [[1,2],[3,5],[7,11]]}
+ it{expect(@a.reshape(nil,2)).to eq [[1,2],[3,5],[7,11]]}
+ it{expect(@a.transpose).to eq [[1,5],[2,7],[3,11]]}
+ it{expect(@a.transpose(1,0)).to eq [[1,5],[2,7],[3,11]]}
+
+ it{expect(@a.sum).to eq 29}
+ it{expect(@a.sum(0)).to eq [6, 9, 14]}
+ it{expect(@a.sum(1)).to eq [6, 23]}
+ if float_types.include?(dtype)
+ it{expect(@a.mean).to eq 29.0/6}
+ it{expect(@a.mean(0)).to eq [3, 4.5, 7]}
+ it{expect(@a.mean(1)).to eq [2, 23.0/3]}
+ end
+ if dtype == Numo::DComplex || dtype == Numo::SComplex
+ it{expect(@a.real).to eq @src}
+ it{expect(@a.imag).to eq [[0]*3]*2}
+ it{expect(@a.conj).to eq @src}
+ it{expect(@a.angle).to eq [[0]*3]*2}
+ else
+ it{expect(@a.min).to eq 1}
+ it{expect(@a.max).to eq 11}
+ it{expect((@a >= 3)).to eq [[0,0,1],[1,1,1]]}
+ it{expect((@a > 3)).to eq [[0,0,0],[1,1,1]]}
+ it{expect((@a <= 3)).to eq [[1,1,1],[0,0,0]]}
+ it{expect((@a < 3)).to eq [[1,1,0],[0,0,0]]}
+ it{expect((@a.eq 3)).to eq [[0,0,1],[0,0,0]]}
+ it{expect(@a.sort).to eq @src}
+ it{expect(@a.sort_index).to eq [[0,1,2],[3,4,5]]}
+ end
+ it{expect(@a.dup.fill(12)).to eq [[12]*3]*2}
+ it{expect((@a + 1)).to eq [[2,3,4],[6,8,12]]}
+ it{expect((@a + [1,2,3])).to eq [[2,4,6],[6,9,14]]}
+ it{expect((@a - 1)).to eq [[0,1,2],[4,6,10]]}
+ it{expect((@a - [1,2,3])).to eq [[0,0,0],[4,5,8]]}
+ it{expect((@a * 3)).to eq [[3,6,9],[15,21,33]]}
+ it{expect((@a * [1,2,3])).to eq [[1,4,9],[5,14,33]]}
+ it{expect((@a / 0.5)).to eq [[2,4,6],[10,14,22]]}
+ it{expect((- at a)).to eq [[-1,-2,-3],[-5,-7,-11]]}
+ it{expect((@a ** 2)).to eq [[1,4,9],[25,49,121]]}
+ it{expect((dtype[[1,0],[0,1]].dot dtype[[4,1],[2,2]])).to eq [[4,1],[2,2]]}
+ it{expect(@a.swap_byte.swap_byte).to eq @src}
+ end
+
+ end
+
+ describe dtype,"[[[1,2],[3,4]],[[5,6],[7,8]]]" do
+ before do
+ @a = dtype[[[1,2],[3,4]],[[5,6],[7,8]]]
+ end
+
+ it{expect(@a[0, 1, 1]).to eq 4}
+ it{expect(@a[:rest]).to eq @a}
+ it{expect(@a[0, :rest]).to eq [[1,2],[3,4]]}
+ it{expect(@a[0, false]).to eq [[1,2],[3,4]]}
+ it{expect(@a[0, 1, :rest]).to eq [3,4]}
+ it{expect(@a[0, 1, false]).to eq [3,4]}
+ it{expect(@a[:rest, 0]).to eq [[1,3],[5,7]]}
+ it{expect(@a[:rest, 0, 1]).to eq [2,6]}
+ it{expect(@a[1, :rest, 0]).to eq [5,7]}
+ it{expect(@a[1, 1, :rest, 0]).to eq 7}
+ it{expect{@a[1, 1, 1, 1, :rest]}.to raise_error IndexError}
+ it{expect{@a[1, 1, 1, :rest, 1]}.to raise_error IndexError}
+ it{expect{@a[:rest, 1, :rest, 0]}.to raise_error IndexError}
+ end
+
+ describe dtype, "#dot" do
+ it "vector.dot(vector)" do
+ a = dtype[1..3]
+ b = dtype[2..4]
+ expect(a.dot(b)).to eq (1*2 + 2*3 + 3*4)
+ end
+ it "matrix.dot(vector)" do
+ a = dtype[1..6].reshape(3,2)
+ b = dtype[1..2]
+ expect(a.dot(b)).to eq [5, 11, 17]
+ end
+ it "vector.dot(matrix)" do
+ a = dtype[1..2]
+ b = dtype[1..6].reshape(2,3)
+ expect(a.dot(b)).to eq [9, 12, 15]
+ end
+ it "matrix.dot(matrix)" do
+ a = dtype[1..6].reshape(3,2)
+ b = dtype[1..6].reshape(2,3)
+ expect(a.dot(b)).to eq [[9, 12, 15], [19, 26, 33], [29, 40, 51]]
+ expect(b.dot(a)).to eq [[22, 28], [49, 64]]
+ end
+ it "matrix.dot(matrix) with incorrect shape" do
+ a = dtype[1..6].reshape(3,2)
+ b = dtype[1..9].reshape(3,3)
+ expect{a.dot(b)}.to raise_error(Numo::NArray::ShapeError)
+ end
+ end
+end
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/ruby-numo-narray.git
More information about the Pkg-ruby-extras-commits
mailing list