Converting a multivariate function to a single variate function

I want to convert a multivariate function into a single variable function. Aka to perform partial differentiation. While my attempt works but it is such an ugly kludge. Is there a better way of doing this?

func1(x,y) = 3.0*x + 7.0*y^2.0

function create1Dfunction(func::Function,vector::Vector,varnum::Int64)
    len = length(vector)
    if 1 <= varnum <= len
        codestring = "("
        for i in 1:len
            if i == varnum
                codestring = codestring * "x"
            else
                codestring = codestring * string(vector[i])
            end
            if i < len
                codestring = codestring * ", "
            end
        end
        codestring = codestring * ")"
        # println(codestring)
        subexpr = Meta.parse(codestring)
        expr = :( x -> $func($subexpr...) )
        # println(expr)
        local OneDimensionalFunc = eval(expr)
        return OneDimensionalFunc
    else
        println("Error, parameter number $(varnum) does not exists")
    end
end

# We want to convert func1(x,y) to g(x) = x -> func1(3.1,x)
println("func1(3.1,7.8) = ",func1(3.1,7.8))
g = create1Dfunction(func1,[3.1,7.8],2)
println("g(7.8) = ",g(7.8))

Output

Starting Julia...
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _  |  |
  | | |_| | | | (_| |  |  Version 1.0.3 (2018-12-18)
 _/ |\__ _|_|_|\__ _|  |  Official https://julialang.org/ release
|__/                   |

func1(3.1,7.8) = 435.18
g(7.8) = 435.18

How about just this:

julia> func1(x, y) = 3.0*x + 7.0*y^2.0
func1 (generic function with 1 method)

julia> g(x) = func1(3.1, x)
g (generic function with 1 method)

julia> func1(3.1, 7.8)
435.18

julia> g(7.8)
435.18
1 Like

What if my function have 26 variables and I want to convert it to a single variable function on variable number 21? And fill the rest with the value [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] and I don’t want to do it by hand. And I don’t know the value of the vector of numbers to replace them with at compile time but only at runtime.

Ah, I see. Here’s an option without dynamic code generation:

oned(f, args, pos) = x -> f(ntuple(i -> i == pos ? x : args[i], length(args))...)

f(x, y) = 3.0*x + 7.0*y^2

g = oned(f, [3.1, 7.8], 2)

And now:

julia> f(3.1, 7.8)
435.18

julia> g(7.8)
435.18
3 Likes

Thank you very much. That worked and is a lot shorter

function oned(f::Function, args::Vector, pos::Int64)
    return x -> f(ntuple(i -> i == pos ? x : args[i], length(args))...)
end
h = oned(func1,[3.1,7.8],2)
println("h(7.8) = ",h(7.8))

Output

Starting Julia...
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _  |  |
  | | |_| | | | (_| |  |  Version 1.0.3 (2018-12-18)
 _/ |\__ _|_|_|\__ _|  |  Official https://julialang.org/ release
|__/                   |

func1(3.1,7.8) = 435.18
g(7.8) = 435.18
h(7.8) = 435.18

Please check my final version of the program

func1(x,y) = 3.0 * x    + 7.0 * y    ^ 2.0
func2(X)   = 3.0 * X[1] + 7.0 * X[2] ^ 2.0

function create1Dfunction(func::Function,args::Vector,pos::Int64;FuncType::String="MultiParameters")
    if 1 <= pos <= length(args)
        if FuncType == "MultiParameters"
            return x -> func( ntuple(i -> i == pos ? x : args[i], length(args))... )
        else
            return x -> func( ntuple(i -> i == pos ? x : args[i], length(args)) )
        end
    else
        println("Error! Parameter number $(pos) does not exists")
        return x -> Nothing
    end
end

# We want to convert func(x,y) to g(x) = x -> func1(3.1,x)
println("func1(3.1,7.8) = ",func1(3.1,7.8))
g = create1Dfunction(func1,[3.1,7.8],2)
println("g(7.8) = ",g(7.8))
h = create1Dfunction(func2,[3.1,7.8],2,FuncType="VectorParameters")
println("h(7.8) = ",h(7.8))

Output

func1(3.1,7.8) = 435.18
g(7.8) = 435.18
h(7.8) = 435.18