Skip to content

argmax with user-defined function #16

@StefanKarpinski

Description

@StefanKarpinski

This is a good benchmark of how well higher-order programming can be optimized, which is something we're actually notably missing in Julia. A basic implementation in Julia was given here:

function argmax(f, itr)
    r = iterate(itr)
    r === nothing && error("empty collection")
    m, state = r
    f_m = f(m)
    while true
        r = iterate(itr, state)
        r === nothing && break
        x, state = r
        f_x = f(x)
        isless(f_m, f_x) || continue
        m, f_m = x, f_x
    end
    return m
end

The really neat part is how tight the resulting machine code can be for a simple user-defined function based on this generic higher-order argmax defintion, e.g.:

rangemax(f, a, b) = argmax(f, min(a,b):max(a,b))

the native code for a call like rangemax(x -> -abs(x-3), -10, 10) is quite efficient:

	cmpq	%rdi, %rsi
	movq	%rdi, %r8
	cmovleq	%rsi, %r8
	cmovlq	%rdi, %rsi
	cmpq	%rsi, %r8
	jne	L23
	movq	%r8, %rax
	retq
L23:
	leaq	-3(%r8), %rax
	movl	$3, %ecx
	subq	%r8, %rcx
	testq	%rax, %rax
	cmovnsq	%rax, %rcx
	negq	%rcx
	movq	%r8, %rax
L48:
	movl	$2, %edi
	subq	%r8, %rdi
	leaq	-2(%r8), %r9
	leaq	1(%r8), %rdx
	testq	%r9, %r9
	cmovnsq	%r9, %rdi
	negq	%rdi
	cmpq	%rdi, %rcx
	cmovlq	%rdx, %rax
	cmovlq	%rdi, %rcx
	movq	%rdx, %r8
	cmpq	%rsi, %rdx
	jne	L48
	retq

This is a case where C may actually have a fairly hard time and C++ will do better using templates. Rust seems like it would do well at this too; most other languages will get killed on this one.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions