下面是在一个范围内绘制函数的代码块,以及在单个输入处:
a = 1.0
f(x::Float64) = -x^2 - a
scatter(f, -3:.1:3)
scatter!([a], [f(a)])
Run Code Online (Sandbox Code Playgroud)
我想绘制与该点相切的线,如下所示:
是否有这样做的模式或简单的工具?
这取决于“模式或简单工具”的含义 - 最简单的方法是手动导出导数,然后将其绘制为函数:
\nhand_gradient(x) = -2x\nRun Code Online (Sandbox Code Playgroud)\n然后添加plot!(hand_gradient, 0:0.01:3)到你的情节中。
当然,对于更复杂的函数或者当您想要绘制大量梯度时,这可能会有点乏味,因此另一种方法是利用 Julia 出色的自动微分功能。比较所有不同的选项有点超出了本答案的范围,但如果您感兴趣,请查看https://juliadiff.org/ 。在这里,我将使用广泛使用的Zygote库:
julia> using Plots, Zygote\n\njulia> a = 1.0;\n\njulia> f(x) = -x^2 - a;\nRun Code Online (Sandbox Code Playgroud)\n[注意,我稍微修改了您的f定义,使其与您发布的图一致,这是一条倒抛物线]
请注意,这里我没有将输入参数的类型限制x为f- 这对于自动微分的工作至关重要,因为它是通过在Dual函数中运行不同的数字类型 (a ) 来实现的。一般来说,以这种方式限制参数类型是 Julia 中的反模式 - 它无助于性能,但会降低您的代码与生态系统其他部分的互操作性,正如您可以在此处看到的,如果您尝试通过f(x::Float64).
现在让我们使用 Zygote 为我们提供梯度:
\njulia> f\'\n#43 (generic function with 1 method)\nRun Code Online (Sandbox Code Playgroud)\n如您所见,运行f\'now 返回一个匿名函数 - 这是 的导数f,您可以通过在特定点评估它来验证:
julia> f\'(2)\n-4.0\nRun Code Online (Sandbox Code Playgroud)\n现在我们需要做的就是利用它来构造一个函数,该函数本身返回一个追踪渐变线的函数:
\njulia> gradient_line(f, x\xe2\x82\x80) = (x -> f(x\xe2\x82\x80) + f\'(x\xe2\x82\x80)*(x-x\xe2\x82\x80))\ngradient_line (generic function with 1 method)\nRun Code Online (Sandbox Code Playgroud)\n该函数接受一个函数f和一个x\xe2\x82\x80我们想要获取其切线的点,然后返回一个匿名函数,该函数返回每个 值处的切线值x。使用它:
julia> default(markerstrokecolor = "white", linewidth = 2);\n\njulia> scatter(f, -3:0.1:3, label = "f(x) = -x\xc2\xb2 - 1", xlabel = "x", ylabel = "f(x)");\n\njulia> scatter!([1], [f(1)], label = "", markersize = 10);\n\njulia> plot!(gradient_line(f, 1), 0:0.1:3, label = "f\'(1)", color = 2);\n\njulia> scatter!([-2], [f(-2)], label = "", markersize = 10, color = 3);\n\njulia> plot!(gradient_line(f, -2), -3:0.1:0, label = "f\'(-2)", color = 3)\nRun Code Online (Sandbox Code Playgroud)\n\n