kumi 0.0.13 → 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rspec +0 -1
- data/BACKLOG.md +34 -0
- data/CLAUDE.md +4 -6
- data/README.md +0 -18
- data/config/functions.yaml +352 -0
- data/docs/dev/analyzer-debug.md +52 -0
- data/docs/dev/parse-command.md +64 -0
- data/docs/functions/analyzer_integration.md +199 -0
- data/docs/functions/signatures.md +171 -0
- data/examples/hash_objects_demo.rb +138 -0
- data/golden/array_operations/schema.kumi +17 -0
- data/golden/cascade_logic/schema.kumi +16 -0
- data/golden/mixed_nesting/schema.kumi +42 -0
- data/golden/simple_math/schema.kumi +10 -0
- data/lib/kumi/analyzer.rb +72 -21
- data/lib/kumi/core/analyzer/checkpoint.rb +72 -0
- data/lib/kumi/core/analyzer/debug.rb +167 -0
- data/lib/kumi/core/analyzer/passes/broadcast_detector.rb +1 -3
- data/lib/kumi/core/analyzer/passes/function_signature_pass.rb +199 -0
- data/lib/kumi/core/analyzer/passes/load_input_cse.rb +120 -0
- data/lib/kumi/core/analyzer/passes/lower_to_ir_pass.rb +72 -157
- data/lib/kumi/core/analyzer/passes/toposorter.rb +37 -1
- data/lib/kumi/core/analyzer/state_serde.rb +64 -0
- data/lib/kumi/core/analyzer/structs/access_plan.rb +12 -10
- data/lib/kumi/core/compiler/access_planner.rb +3 -2
- data/lib/kumi/core/function_registry/collection_functions.rb +3 -1
- data/lib/kumi/core/functions/dimension.rb +98 -0
- data/lib/kumi/core/functions/dtypes.rb +20 -0
- data/lib/kumi/core/functions/errors.rb +11 -0
- data/lib/kumi/core/functions/kernel_adapter.rb +45 -0
- data/lib/kumi/core/functions/loader.rb +119 -0
- data/lib/kumi/core/functions/registry_v2.rb +68 -0
- data/lib/kumi/core/functions/shape.rb +70 -0
- data/lib/kumi/core/functions/signature.rb +122 -0
- data/lib/kumi/core/functions/signature_parser.rb +86 -0
- data/lib/kumi/core/functions/signature_resolver.rb +272 -0
- data/lib/kumi/core/ir/execution_engine/interpreter.rb +98 -7
- data/lib/kumi/core/ir/execution_engine/profiler.rb +202 -0
- data/lib/kumi/dev/ir.rb +75 -0
- data/lib/kumi/dev/parse.rb +105 -0
- data/lib/kumi/dev/runner.rb +83 -0
- data/lib/kumi/frontends/ruby.rb +28 -0
- data/lib/kumi/frontends/text.rb +46 -0
- data/lib/kumi/frontends.rb +29 -0
- data/lib/kumi/kernels/ruby/aggregate_core.rb +105 -0
- data/lib/kumi/kernels/ruby/datetime_scalar.rb +21 -0
- data/lib/kumi/kernels/ruby/mask_scalar.rb +15 -0
- data/lib/kumi/kernels/ruby/scalar_core.rb +63 -0
- data/lib/kumi/kernels/ruby/string_scalar.rb +19 -0
- data/lib/kumi/kernels/ruby/vector_struct.rb +39 -0
- data/lib/kumi/runtime/executable.rb +57 -26
- data/lib/kumi/schema.rb +4 -4
- data/lib/kumi/support/diff.rb +22 -0
- data/lib/kumi/support/ir_render.rb +61 -0
- data/lib/kumi/version.rb +1 -1
- data/lib/kumi.rb +2 -0
- data/performance_results.txt +63 -0
- data/scripts/test_mixed_nesting_performance.rb +206 -0
- metadata +45 -5
- data/docs/features/javascript-transpiler.md +0 -148
- data/lib/kumi/js.rb +0 -23
- data/lib/kumi/support/ir_dump.rb +0 -491
data/lib/kumi/dev/ir.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
module Kumi
|
6
|
+
module Dev
|
7
|
+
module IR
|
8
|
+
module_function
|
9
|
+
|
10
|
+
def to_text(ir_module)
|
11
|
+
raise "nil IR" unless ir_module
|
12
|
+
|
13
|
+
lines = []
|
14
|
+
lines << "IR Module"
|
15
|
+
lines << "decls: #{ir_module.decls.size}"
|
16
|
+
|
17
|
+
ir_module.decls.each_with_index do |decl, i|
|
18
|
+
lines << "decl[#{i}] #{decl.kind}:#{decl.name} shape=#{decl.shape} ops=#{decl.ops.size}"
|
19
|
+
|
20
|
+
decl.ops.each_with_index do |op, j|
|
21
|
+
# Sort attribute keys for deterministic output
|
22
|
+
sorted_attrs = op.attrs.keys.sort.map { |k| "#{k}=#{format_value(op.attrs[k])}" }.join(" ")
|
23
|
+
args_str = op.args.inspect
|
24
|
+
lines << " #{j}: #{op.tag} #{sorted_attrs} #{args_str}".rstrip
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
lines.join("\n") + "\n"
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def self.format_value(val)
|
34
|
+
case val
|
35
|
+
when true, false
|
36
|
+
val.to_s
|
37
|
+
when Symbol
|
38
|
+
":#{val}"
|
39
|
+
when Array
|
40
|
+
val.inspect
|
41
|
+
else
|
42
|
+
val.to_s
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_json(ir_module, pretty: true)
|
47
|
+
raise "nil IR" unless ir_module
|
48
|
+
|
49
|
+
data = {
|
50
|
+
inputs: ir_module.inputs,
|
51
|
+
decls: ir_module.decls.map do |decl|
|
52
|
+
{
|
53
|
+
name: decl.name,
|
54
|
+
kind: decl.kind,
|
55
|
+
shape: decl.shape,
|
56
|
+
ops: decl.ops.map do |op|
|
57
|
+
{
|
58
|
+
tag: op.tag,
|
59
|
+
attrs: op.attrs,
|
60
|
+
args: op.args
|
61
|
+
}
|
62
|
+
end
|
63
|
+
}
|
64
|
+
end
|
65
|
+
}
|
66
|
+
|
67
|
+
if pretty
|
68
|
+
JSON.pretty_generate(data)
|
69
|
+
else
|
70
|
+
JSON.generate(data)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fileutils"
|
4
|
+
|
5
|
+
module Kumi
|
6
|
+
module Dev
|
7
|
+
module Parse
|
8
|
+
module_function
|
9
|
+
|
10
|
+
def run(schema_path, opts = {})
|
11
|
+
# Load schema via text frontend
|
12
|
+
begin
|
13
|
+
schema, _inputs = Kumi::Frontends::Text.load(path: schema_path)
|
14
|
+
rescue LoadError => e
|
15
|
+
puts "Error: kumi-parser gem not available. Install: gem install kumi-parser"
|
16
|
+
return false
|
17
|
+
rescue StandardError => e
|
18
|
+
puts "Parse error: #{e.message}"
|
19
|
+
return false
|
20
|
+
end
|
21
|
+
|
22
|
+
# Run analyzer
|
23
|
+
runner_opts = opts.slice(:trace, :snap, :snap_dir, :resume_from, :resume_at, :stop_after)
|
24
|
+
res = Dev::Runner.run(schema, runner_opts)
|
25
|
+
|
26
|
+
unless res.ok?
|
27
|
+
puts "Analysis errors:"
|
28
|
+
res.errors.each { |err| puts " #{err}" }
|
29
|
+
return false
|
30
|
+
end
|
31
|
+
|
32
|
+
unless res.ir
|
33
|
+
puts "Error: No IR generated"
|
34
|
+
return false
|
35
|
+
end
|
36
|
+
|
37
|
+
# Report trace file if enabled
|
38
|
+
if opts[:trace] && res.respond_to?(:trace_file)
|
39
|
+
puts "Trace written to: #{res.trace_file}"
|
40
|
+
end
|
41
|
+
|
42
|
+
# Determine file extension and renderer
|
43
|
+
extension = opts[:json] ? "json" : "txt"
|
44
|
+
golden_path = File.join(File.dirname(schema_path), "expected", "ir.#{extension}")
|
45
|
+
|
46
|
+
# Render IR
|
47
|
+
rendered = if opts[:json]
|
48
|
+
Dev::IR.to_json(res.ir, pretty: true)
|
49
|
+
else
|
50
|
+
Dev::IR.to_text(res.ir)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Handle write mode
|
54
|
+
if opts[:write]
|
55
|
+
FileUtils.mkdir_p(File.dirname(golden_path))
|
56
|
+
File.write(golden_path, rendered)
|
57
|
+
puts "Wrote: #{golden_path}"
|
58
|
+
return true
|
59
|
+
end
|
60
|
+
|
61
|
+
# Handle update mode (write only if different)
|
62
|
+
if opts[:update]
|
63
|
+
if File.exist?(golden_path) && File.read(golden_path) == rendered
|
64
|
+
puts "No changes (#{golden_path})"
|
65
|
+
return true
|
66
|
+
else
|
67
|
+
FileUtils.mkdir_p(File.dirname(golden_path))
|
68
|
+
File.write(golden_path, rendered)
|
69
|
+
puts "Updated: #{golden_path}"
|
70
|
+
return true
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Handle no-diff mode
|
75
|
+
if opts[:no_diff]
|
76
|
+
puts rendered
|
77
|
+
return true
|
78
|
+
end
|
79
|
+
|
80
|
+
# Default: diff mode (same as write but show diff instead)
|
81
|
+
if File.exist?(golden_path)
|
82
|
+
# Use diff directly with the golden file path
|
83
|
+
require "tempfile"
|
84
|
+
Tempfile.create(["actual", File.extname(golden_path)]) do |actual_file|
|
85
|
+
actual_file.write(rendered)
|
86
|
+
actual_file.flush
|
87
|
+
|
88
|
+
result = `diff -u --label=expected --label=actual #{golden_path} #{actual_file.path}`
|
89
|
+
if result.empty?
|
90
|
+
puts "No changes (#{golden_path})"
|
91
|
+
return true
|
92
|
+
else
|
93
|
+
puts result.chomp
|
94
|
+
return false
|
95
|
+
end
|
96
|
+
end
|
97
|
+
else
|
98
|
+
# No golden file exists, just print the output
|
99
|
+
puts rendered
|
100
|
+
return true
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kumi
|
4
|
+
module Dev
|
5
|
+
module Runner
|
6
|
+
Result = Struct.new(:state, :ir, :errors, keyword_init: true) do
|
7
|
+
def ok?
|
8
|
+
errors.empty?
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module_function
|
13
|
+
|
14
|
+
def run(schema, opts = {})
|
15
|
+
# Set ENV vars for debug/checkpoint based on opts
|
16
|
+
setup_env_vars(opts)
|
17
|
+
|
18
|
+
state = Core::Analyzer::AnalysisState.new
|
19
|
+
errors = []
|
20
|
+
|
21
|
+
begin
|
22
|
+
final_state = Kumi::Analyzer.run_analysis_passes(schema, Kumi::Analyzer::DEFAULT_PASSES, state, errors)
|
23
|
+
ir = final_state[:ir_module]
|
24
|
+
|
25
|
+
result = Result.new(
|
26
|
+
state: final_state,
|
27
|
+
ir: ir,
|
28
|
+
errors: errors
|
29
|
+
)
|
30
|
+
|
31
|
+
# Report trace file if enabled
|
32
|
+
if opts[:trace] && defined?(@trace_file) && @trace_file
|
33
|
+
trace_file_path = @trace_file
|
34
|
+
result.define_singleton_method(:trace_file) { trace_file_path }
|
35
|
+
end
|
36
|
+
|
37
|
+
result
|
38
|
+
rescue StandardError => e
|
39
|
+
# Convert exception to error if not already captured
|
40
|
+
errors << e.message unless errors.include?(e.message)
|
41
|
+
Result.new(
|
42
|
+
state: state,
|
43
|
+
ir: nil,
|
44
|
+
errors: errors
|
45
|
+
)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def self.setup_env_vars(opts)
|
52
|
+
if opts[:trace]
|
53
|
+
ENV["KUMI_DEBUG_STATE"] = "1"
|
54
|
+
trace_file = ENV["KUMI_DEBUG_FILE"] || "tmp/state_trace.jsonl"
|
55
|
+
ENV["KUMI_DEBUG_FILE"] = trace_file
|
56
|
+
|
57
|
+
# Store for later reporting
|
58
|
+
@trace_file = trace_file
|
59
|
+
end
|
60
|
+
|
61
|
+
if opts[:snap]
|
62
|
+
ENV["KUMI_CHECKPOINT_PHASES"] = opts[:snap]
|
63
|
+
end
|
64
|
+
|
65
|
+
if opts[:snap_dir]
|
66
|
+
ENV["KUMI_CHECKPOINT_DIR"] = opts[:snap_dir]
|
67
|
+
end
|
68
|
+
|
69
|
+
if opts[:resume_from]
|
70
|
+
ENV["KUMI_CHECKPOINT_RESUME_FROM"] = opts[:resume_from]
|
71
|
+
end
|
72
|
+
|
73
|
+
if opts[:resume_at]
|
74
|
+
ENV["KUMI_CHECKPOINT_RESUME_AT"] = opts[:resume_at]
|
75
|
+
end
|
76
|
+
|
77
|
+
if opts[:stop_after]
|
78
|
+
ENV["KUMI_CHECKPOINT_STOP_AFTER"] = opts[:stop_after]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kumi
|
4
|
+
module Frontends
|
5
|
+
module Ruby
|
6
|
+
module_function
|
7
|
+
|
8
|
+
def load(path:, inputs: {})
|
9
|
+
mod = Module.new
|
10
|
+
mod.extend(Kumi::Schema)
|
11
|
+
mod.module_eval(File.read(path), path)
|
12
|
+
|
13
|
+
# Extract just the syntax tree AST (same as Text frontend)
|
14
|
+
schema_ast = if mod.const_defined?(:GoldenSchema)
|
15
|
+
golden = mod.const_get(:GoldenSchema)
|
16
|
+
golden.build if golden.respond_to?(:build)
|
17
|
+
golden.__syntax_tree__
|
18
|
+
elsif mod.__syntax_tree__
|
19
|
+
mod.__syntax_tree__
|
20
|
+
else
|
21
|
+
raise "No schema AST found. Make sure the .rb file calls 'schema do...end'"
|
22
|
+
end
|
23
|
+
|
24
|
+
[schema_ast, inputs]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kumi
|
4
|
+
module Frontends
|
5
|
+
module Text
|
6
|
+
module_function
|
7
|
+
|
8
|
+
def load(path:, inputs: {})
|
9
|
+
src = File.read(path)
|
10
|
+
|
11
|
+
begin
|
12
|
+
require "kumi-parser"
|
13
|
+
ast = Kumi::Parser::TextParser.parse(src)
|
14
|
+
Core::Analyzer::Debug.info(:parse, kind: :text, file: path, ok: true) if Core::Analyzer::Debug.enabled?
|
15
|
+
[ast, inputs]
|
16
|
+
rescue LoadError
|
17
|
+
raise "kumi-parser gem not available. Install: gem install kumi-parser"
|
18
|
+
rescue StandardError => e
|
19
|
+
loc = (e.respond_to?(:location) && e.location) || {}
|
20
|
+
line, col = loc.values_at(:line, :column)
|
21
|
+
snippet = self.code_frame(src, line, col)
|
22
|
+
raise StandardError, "#{path}:#{line || '?'}:#{col || '?'}: #{e.message}\n#{snippet}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def self.code_frame(src, line, col, context: 2)
|
29
|
+
return "" unless line
|
30
|
+
|
31
|
+
lines = src.lines
|
32
|
+
from = [line - 1 - context, 0].max
|
33
|
+
to = [line - 1 + context, lines.length - 1].min
|
34
|
+
out = []
|
35
|
+
|
36
|
+
(from..to).each do |i|
|
37
|
+
prefix = (i + 1 == line) ? "➤" : " "
|
38
|
+
out << "#{prefix} %4d | %s" % [i + 1, lines[i].rstrip]
|
39
|
+
out << " | %s^" % (" " * (col - 1)) if i + 1 == line && col
|
40
|
+
end
|
41
|
+
|
42
|
+
out.join("\n")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kumi
|
4
|
+
module Frontends
|
5
|
+
def self.load(path:, inputs: {})
|
6
|
+
mode = (ENV["KUMI_PARSER"] || "auto") # auto|text|ruby
|
7
|
+
ext = File.extname(path)
|
8
|
+
|
9
|
+
# Explicit mode selection
|
10
|
+
return Text.load(path:, inputs:) if mode == "text"
|
11
|
+
return Ruby.load(path:, inputs:) if mode == "ruby"
|
12
|
+
|
13
|
+
# Auto mode: prefer .kumi if present
|
14
|
+
if mode == "auto" && ext == ".rb"
|
15
|
+
kumi_path = path.sub(/\.rb\z/, ".kumi")
|
16
|
+
if File.exist?(kumi_path)
|
17
|
+
return Text.load(path: kumi_path, inputs: inputs)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# File extension based selection
|
22
|
+
return Text.load(path:, inputs:) if ext == ".kumi"
|
23
|
+
return Ruby.load(path:, inputs:) if ext == ".rb"
|
24
|
+
|
25
|
+
# Default fallback
|
26
|
+
Ruby.load(path:, inputs:)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kumi
|
4
|
+
module Kernels
|
5
|
+
module Ruby
|
6
|
+
module AggregateCore
|
7
|
+
module_function
|
8
|
+
|
9
|
+
def kumi_sum(enum, skip_nulls: true, min_count: 0)
|
10
|
+
total = 0
|
11
|
+
count = 0
|
12
|
+
enum.each do |x|
|
13
|
+
next if skip_nulls && x.nil?
|
14
|
+
|
15
|
+
total += x
|
16
|
+
count += 1
|
17
|
+
end
|
18
|
+
return nil if count < min_count
|
19
|
+
|
20
|
+
total
|
21
|
+
end
|
22
|
+
|
23
|
+
def kumi_min(enum, skip_nulls: true, min_count: 0)
|
24
|
+
best = nil
|
25
|
+
count = 0
|
26
|
+
enum.each do |x|
|
27
|
+
next if skip_nulls && x.nil?
|
28
|
+
|
29
|
+
best = x if best.nil? || x < best
|
30
|
+
count += 1
|
31
|
+
end
|
32
|
+
return nil if count < min_count
|
33
|
+
|
34
|
+
best
|
35
|
+
end
|
36
|
+
|
37
|
+
def kumi_max(enum, skip_nulls: true, min_count: 0)
|
38
|
+
best = nil
|
39
|
+
count = 0
|
40
|
+
enum.each do |x|
|
41
|
+
next if skip_nulls && x.nil?
|
42
|
+
|
43
|
+
best = x if best.nil? || x > best
|
44
|
+
count += 1
|
45
|
+
end
|
46
|
+
return nil if count < min_count
|
47
|
+
|
48
|
+
best
|
49
|
+
end
|
50
|
+
|
51
|
+
def kumi_mean(enum, skip_nulls: true, min_count: 0)
|
52
|
+
total = 0.0
|
53
|
+
count = 0
|
54
|
+
enum.each do |x|
|
55
|
+
next if skip_nulls && x.nil?
|
56
|
+
|
57
|
+
total += x
|
58
|
+
count += 1
|
59
|
+
end
|
60
|
+
return nil if count < [min_count, 1].max
|
61
|
+
|
62
|
+
total / count
|
63
|
+
end
|
64
|
+
|
65
|
+
def kumi_any(enum, skip_nulls: true, min_count: 0)
|
66
|
+
count = 0
|
67
|
+
enum.each do |x|
|
68
|
+
next if skip_nulls && x.nil?
|
69
|
+
|
70
|
+
return true if x
|
71
|
+
count += 1
|
72
|
+
end
|
73
|
+
return nil if count < min_count
|
74
|
+
|
75
|
+
false
|
76
|
+
end
|
77
|
+
|
78
|
+
def kumi_all(enum, skip_nulls: true, min_count: 0)
|
79
|
+
count = 0
|
80
|
+
enum.each do |x|
|
81
|
+
next if skip_nulls && x.nil?
|
82
|
+
|
83
|
+
return false unless x
|
84
|
+
count += 1
|
85
|
+
end
|
86
|
+
return nil if count < min_count
|
87
|
+
|
88
|
+
true
|
89
|
+
end
|
90
|
+
|
91
|
+
def kumi_count(enum, skip_nulls: true, min_count: 0)
|
92
|
+
count = 0
|
93
|
+
enum.each do |x|
|
94
|
+
next if skip_nulls && x.nil?
|
95
|
+
|
96
|
+
count += 1
|
97
|
+
end
|
98
|
+
return nil if count < min_count
|
99
|
+
|
100
|
+
count
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "date"
|
4
|
+
|
5
|
+
module Kumi
|
6
|
+
module Kernels
|
7
|
+
module Ruby
|
8
|
+
module DatetimeScalar
|
9
|
+
module_function
|
10
|
+
|
11
|
+
def dt_add_days(d, n)
|
12
|
+
d + n
|
13
|
+
end
|
14
|
+
|
15
|
+
def dt_diff_days(d1, d2)
|
16
|
+
(d1 - d2).to_i
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kumi
|
4
|
+
module Kernels
|
5
|
+
module Ruby
|
6
|
+
module ScalarCore
|
7
|
+
module_function
|
8
|
+
|
9
|
+
def kumi_add(a, b)
|
10
|
+
a + b
|
11
|
+
end
|
12
|
+
|
13
|
+
def kumi_sub(a, b)
|
14
|
+
a - b
|
15
|
+
end
|
16
|
+
|
17
|
+
def kumi_mul(a, b)
|
18
|
+
a * b
|
19
|
+
end
|
20
|
+
|
21
|
+
def kumi_div(a, b)
|
22
|
+
a / b.to_f
|
23
|
+
end
|
24
|
+
|
25
|
+
def kumi_eq(a, b)
|
26
|
+
a == b
|
27
|
+
end
|
28
|
+
|
29
|
+
def kumi_gt(a, b)
|
30
|
+
a > b
|
31
|
+
end
|
32
|
+
|
33
|
+
def kumi_gte(a, b)
|
34
|
+
a >= b
|
35
|
+
end
|
36
|
+
|
37
|
+
def kumi_lt(a, b)
|
38
|
+
a < b
|
39
|
+
end
|
40
|
+
|
41
|
+
def kumi_lte(a, b)
|
42
|
+
a <= b
|
43
|
+
end
|
44
|
+
|
45
|
+
def kumi_ne(a, b)
|
46
|
+
a != b
|
47
|
+
end
|
48
|
+
|
49
|
+
def kumi_and(a, b)
|
50
|
+
a && b
|
51
|
+
end
|
52
|
+
|
53
|
+
def kumi_or(a, b)
|
54
|
+
a || b
|
55
|
+
end
|
56
|
+
|
57
|
+
def kumi_not(a)
|
58
|
+
!a
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kumi
|
4
|
+
module Kernels
|
5
|
+
module Ruby
|
6
|
+
module VectorStruct
|
7
|
+
module_function
|
8
|
+
|
9
|
+
def size(vec)
|
10
|
+
vec&.size
|
11
|
+
end
|
12
|
+
|
13
|
+
def join_zip(left, right)
|
14
|
+
raise NotImplementedError, "join operations should be implemented in IR/VM"
|
15
|
+
end
|
16
|
+
|
17
|
+
def join_product(left, right)
|
18
|
+
raise NotImplementedError, "join operations should be implemented in IR/VM"
|
19
|
+
end
|
20
|
+
|
21
|
+
def align_to(vec, target_axes)
|
22
|
+
raise NotImplementedError, "align_to should be implemented in IR/VM"
|
23
|
+
end
|
24
|
+
|
25
|
+
def lift(vec, indices)
|
26
|
+
raise NotImplementedError, "lift should be implemented in IR/VM"
|
27
|
+
end
|
28
|
+
|
29
|
+
def flatten(*args)
|
30
|
+
raise NotImplementedError, "flatten should be implemented in IR/VM"
|
31
|
+
end
|
32
|
+
|
33
|
+
def take(values, indices)
|
34
|
+
raise NotImplementedError, "take should be implemented in IR/VM"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|