# Slow plotting of trigonometric functions

I have two sets of solutions for a and b. I'm plotting solution only if it is positive for both a and b.

 a = 2; b = 3;
solutionsA[x_, a_, b_] = {a Sin[b*x], a Sin[b*x + Pi/2], a Sin[b*x + Pi]};
solutionsB[x_, a_, b_] = {a Tan[b*x], a Tan[b*x + Pi/2], a Tan[b*x + Pi]};
Plot[Select[
Transpose[
{solutionsA[x, a, b], solutionsB[x, a, b]}
]
, (#[[1]] > 0 && #[[2]] > 0 ) &]
, {x, 0, 10}, Exclusions -> {Cos[b*x] == 0, Sin[b*x] == 0}]


My output is very slow. Why?

-
@Öskå Is it possible to do the same without Select ? –  Филипп Цветков Nov 1 '13 at 11:20
@илипп Not that I know, but there must be different ways that others might know about. –  Öskå Nov 1 '13 at 11:28

You can get it about 5-6 times faster if you define a separate function (to do Transpose just once):

ClearAll[f];
f[x_?NumericQ] =
# * UnitStep[First @ #] * UnitStep[Last @ #] & /@
Transpose[{solutionsA[x, a, b], solutionsB[x, a, b]}],


and the presence of UnitStep makes Select unnecessary, with visually the same output. You can then plot it as e.g.

Plot[f[x], {x, 0, 10}, Exclusions -> {Cos[b*x] == 0, Sin[b*x] == 0}, PlotRange -> {Automatic, {0, 7}}]


A cleaner way to do this is to have a function generator that would embed your parameters, so that you don't have a dependence on global variables a and b:

makeF[a_, b_] :=
Function[
x,
# * UnitStep[First @ #] * UnitStep[Last @ #] & /@
Transpose[{solutionsA[x, a, b], solutionsB[x, a, b]}]
]


and then

ClearAll[f];
f = makeF[a,b]


and then use f as before.

To get some further speed-up, you can compile this. Here is the corresponding function generator:

ClearAll[makeFC];
makeFC[a_, b_, opts___?OptionQ] :=
Block[{x},Compile[x, Evaluate[makeF[a, b][x], opts]]]


Now you can do

fc = makeFC[a, b];


and then plot fc. I can't test now, but presumably by passing CompilationTarget -> "C" to makeFC, you can get the plotting faster still.

-

A solution which outperforms the currently given answers is the following: You build up the complete expression of your function using Which, so that you have in the end

tuned[x_]:=Which[
Positive[Sin[3 x]]&&Positive[Tan[3 x]],{2 Sin[3 x],2 Tan[3 x]},
Positive[Cos[3 x]]&&Positive[-Cot[3 x]],{2 Cos[3 x],-2 Cot[3 x]},
Positive[-Sin[3 x]]&&Positive[Tan[3 x]],{-2 Sin[3 x],2 Tan[3 x]},
True,None]


This approach works even if you don't know specific values for a and b. To get the definition of tuned automatically from you two solutionsA and solutionsB the following injection code can be used:

With[{arg = Transpose[{solutionsA[x, a, b], solutionsB[x, a, b]}]},
(tuned[x_] := #) & [
Which @@ Sequence @@@ Append[{And @@ (Positive[#]), #} & /@ arg, {True, None}]]
]


On my machine, creating the graphics 10x gives the following timings for the different answers (I'm on my desktop pc now, so timings are in general faster):

• my approach 0.46 seconds. If I tweak it with Compile (see below) we can improve it to 0.21 seconds.
• the original approach of the OP takes 7.71 seconds.
• Leonid's compiled version 0.59 seconds and when you compile it to "C" then 0.55 seconds
• chyaongs needs 0.61 seconds

For testing, I iterated your original Plot command and measured the AbsoluteTiming. Let me point out that all current answers use the same approach and the tweaking to improve from 0.6 to 0.2 seconds isn't really worth it.

Let me give the code of my compiled version for comparison

With[{arg = Transpose[{solutionsA[x, a, b], solutionsB[x, a, b]}]},
tunedC = Compile[{{x, _Real}}, #] &[
Which @@
Sequence @@@
Append[{And @@ (Positive[#]), #} & /@ arg, {True, {0., 0.}}]]]

-
Did you test my compiled approach? Particularly, compiled to C? –  Leonid Shifrin Nov 1 '13 at 14:46
@LeonidShifrin I get for 10 runs (on my desktop PC now) for your compiled version 0.589 s, compiled to "C" 0.5604 and my version gives me 0.460. –  halirutan Nov 1 '13 at 15:20
@LeonidShifrin When I create a compiled version from my Which code, giving back {0.0, 0.0} instead of None, it runs in only 0.21 sec. –  halirutan Nov 1 '13 at 15:26
Thanks for the data. I already voted for your answer, in any case :) –  Leonid Shifrin Nov 1 '13 at 16:20
a = 2; b = 3;
solutions[f_, a_: a, b_: b] = a {f[b*x], f[b*x + Pi/2], f[b*x + Pi]};
expr = If[#1 > 0 && #2 > 0, {##}] & @@@ Transpose[solutions /@ {Sin, Tan}]
Plot[expr, {x, 0, 10}, Exclusions -> {Cos[b*x] == 0, Sin[b*x] == 0}]


-

A nice compact one, using the two argument form of UnitStep and summing the solutions:

sol = Total @ MapThread[UnitStep[##] {##} &, {solutionsA[x, a, b], solutionsB[x, a, b]}]

Block[{a = 2, b = 3}, Plot[sol, {x, 0, 10}, Exclusions -> {Cos[b*x] == 0, Sin[b*x] == 0}]]


-