Plotting 2 functions

Hi, Im trying to plot my Chebyshev approximation

using Printf
using Plots
pyplot()

mutable struct Cheb_struct
    c::Vector{Float64}
    min::Float64
    max::Float64
end

function cheb_coeff(min::Float64, max::Float64, n::Int, fn::Function)::Cheb_struct
    struc = Cheb_struct(Vector{Float64}(undef,n), min, max)
    f = Vector{Float64}(undef,n)
    p = Vector{Float64}(undef,n)
    max_plus_min = (max + min) / 2
    max_minus_min = (max - min) / 2
    for k in 0:n-1
        p[k+1] = pi * ((k+1) - 0.5) / n
        f[k+1] = fn(max_plus_min + cos(p[k+1])*max_minus_min)
    end
    n2 = 2 / n
    for j in 0:n-1
        s = 0
        for i in 0:n-1
            s += f[i+1]*cos(j*p[i+1])
        struc.c[j+1] = s * n2
    end
end
    return struc
end

function approximate(struc::Cheb_struct, x::Float64)::Float64
    x1 = (2*x - struc.max - struc.min) / (struc.max - struc.min)
    x2 = 2*x1
    t = s = 0
    for j in length(struc.c):-1:2
        pom = s
        s = x2 * s - t + struc.c[j]
        t = pom
    end
    return (x1 * s - t + struc.c[1] / 2)
end

fn = sin
struc  = cheb_coeff(0.0, 1.0, 10, fn)
println("coeff:")

for i in struc.c
    @printf("% .15f\n", i)
end

println("\n     x         eval          approx      eval-approx")
for x in struc.min:0.1:struc.max
    ev= fn(x)
    approx= approximate(struc, x)
    @printf("%12.8f %12.8f  %12.8f   % .3e\n", x,ev, approx,  ev-approx)
    p =plot(ev,approx)
    display(p)
end

But I´m getting error:

ERROR: LoadError: Cannot convert Float64 to series data for plotting
Stacktrace:
 [1] error(::String) at .\error.jl:33
 [2] prepareSeriesData(::Float64) at C:\Users\wunsc\.julia\packages\Plots\Ih71u\src\series.jl:13
 [3] convertToAnyVector(::Float64) at C:\Users\wunsc\.julia\packages\Plots\Ih71u\src\series.jl:24
 [4] macro expansion at C:\Users\wunsc\.julia\packages\Plots\Ih71u\src\series.jl:113 [inlined]
 [5] apply_recipe(::Dict{Symbol,Any}, ::Type{Plots.SliceIt}, ::Float64, ::Float64, ::Nothing) at C:\Users\wunsc\.julia\packages\RecipesBase\zBoFG\src\RecipesBase.jl:275
 [6] _process_userrecipes(::Plots.Plot{Plots.PyPlotBackend}, ::Dict{Symbol,Any}, ::Tuple{Float64,Float64}) at C:\Users\wunsc\.julia\packages\Plots\Ih71u\src\pipeline.jl:83
 [7] _plot!(::Plots.Plot{Plots.PyPlotBackend}, ::Dict{Symbol,Any}, ::Tuple{Float64,Float64}) at C:\Users\wunsc\.julia\packages\Plots\Ih71u\src\plot.jl:178
 [8] #plot#133(::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, ::typeof(plot), ::Float64, ::Vararg{Float64,N} where N) at C:\Users\wunsc\.julia\packages\Plots\Ih71u\src\plot.jl:57
 [9] plot(::Float64, ::Float64) at C:\Users\wunsc\.julia\packages\Plots\Ih71u\src\plot.jl:51
 [10] top-level scope at C:\Users\wunsc\Desktop\Julia\test.jl:57
 [11] include at .\boot.jl:328 [inlined]
 [12] include_relative(::Module, ::String) at .\loading.jl:1094
 [13] include(::Module, ::String) at .\Base.jl:31
 [14] include(::String) at .\client.jl:431
 [15] top-level scope at REPL[2]:1
in expression starting at C:\Users\wunsc\Desktop\Julia\test.jl:53

I would be very grateful if someone could help me to plot these two functions.

ev= fn(x)

this makes it a single number?..(as what the error msg is trying to tell you

Probably you want something like:

x = struc.min:0.1:struc.max
plot(x, [ fn.(x),  approximate.(struc, x) ])

to evaluate your fn and its approximation for an array of points and plot them both vs. x.

I tried that but now Im getting

ERROR: LoadError: MethodError: no method matching length(::Cheb_struct)
Closest candidates are:
  length(::Core.SimpleVector) at essentials.jl:597
  length(::Base.MethodList) at reflection.jl:819
  length(::Core.MethodTable) at reflection.jl:893

try

approximate.(Ref(struc), x)

An alternative syntax in Plots is to pass the anonymous functions and extrema:

plot([ fn,  t -> approximate(struc, t) ], struc.min, struc.max)

and Plots will figure out a good set of points to evaluate the function on. It’s mainly useful if the functions have some singular points where denser sampling is needed.

Thank you very much, both of these approaches worked.

Since I’m guessing you are doing this as a learning exercise (the ApproxFun package already implements Chebyshev approximation in a much more complete way), let me give a few suggestions.

Note, by the way, that these type declarations don’t actually help you. It would be more flexible, and just as fast, to just use function approximate(struc::Cheb_struct, x::Number). Whenever you call a function, Julia’s compiler specializes it for the given argument types and compiles a type-specialized version.

Similarlly for

function cheb_coeff(min::Float64, max::Float64, n::Int, fn::Function)::Cheb_struct

Overspecifying the argument types like this makes your function unnecessarily inflexible without making it any faster. A key strength of Julia is that you can write code that is simultaneously type-generic and fast.

(Since this is a constructor function, you would normally name it after the type. i.e. call the function function Cheb_struct(...).)

I assume that you realize you are using an O(n^2) algorithm whereas it’s possible to construct the Chebyshev coefficients in O(n\log n) operations using FFTs. The FFTW.jl package provides fast DCT routines that are suited to Chebyshev approximation.

This is a type instability and will hurt performance. Instead, use the type of x2:

t = s = zero(x2)

Note also that for this sort of thing you can make Cheb_struct callable instead:

function (struc::Cheb_struct)(x::Real)
    ...
end

Then you can just do struc(x) instead of approximate(struc, x), and struc.(x) to operate on an array.

mutable struct Cheb_struct
    c::Vector{Float64}
    min::Float64
    max::Float64
end

As far as I can tell there is no need for this to be mutable. You can change the elements of c even if the struct is not mutable, because a Vector is a mutable container. Also, in general for something like this I would recommend parameterizing the type, i.e.

struct Cheb{T<:AbstractFloat}
    c::Vector{T}
    min::T
    max::T
end

(omitting _struct from the name since CamelCase names in Julia typically denote types or modules.)

3 Likes