3

I guess this is more of an informatic question. A quite complicated function of mine generates me a list of valid points, depending on a parameter, like this:

valid[g_?NumericQ] := Table[g^(i/6), {i, If[g < 1.5, 2, If[g < 2, 4, 6]]}]

valid[1]
{1, 1}

valid[1.3]
{1.0447, 1.09139}

valid[1.6]
{1.08148, 1.16961, 1.26491, 1.36798}

valid[2.1]
{1.13163, 1.28058, 1.44914, 1.63988, 1.85574, 2.1}

So the number of valid points is variable (between 2 and 6). So what I want to do now is to plot these efficiently. What I inefficiently did was

v1=DiscretePlot[valid[g][[1]],{g,1,3,0.01}]
v2=DiscretePlot[valid[g][[2]],{g,1,3,0.01}]
v3=DiscretePlot[valid[g][[3]],{g,1,3,0.01}]
v4=DiscretePlot[valid[g][[4]],{g,1,3,0.01}]
v5=DiscretePlot[valid[g][[5]],{g,1,3,0.01}]
v6=DiscretePlot[valid[g][[6]],{g,1,3,0.01}]
Show[v1, v2, v3, v4, v5, v6, PlotRange -> {{1, 3}, {1, 3}}]

which, as you can imagine, takes quite a while, since Mathematica has to calculate valid[g] six times instead of one. I played around with Module, but that didn't work out for me. As a clarification, what "Show" gives me is pretty much what I want; I just would like a more efficient solution.

EDIT:
Ok, so what I do now, I let him generate the Table with all values once:

valid[g_?NumericQ] := PadRight[Table[g^(i/6), {i, If[g < 1.5, 2, If[g < 2, 4, 6]]}],6,Missing[]]

validg = Table[ valid[g],{g,1,3,0.01}]

and then I do the partial DiscretePlots:. Ok, that should work! Thank you all :)

EDiT2: Though i'm fine with the solution, you might not be, so i'll give a further constraint: i can not really change "valid[]", but have to work with it's output, since it is based on this: Updating Wagon's FindAllCrossings2D[] function

Peter
  • 65
  • 7
  • valid[1.5] will not have a third element, so valid[1.5][[3]] should not work in your plot, no? Consider using Indeterminate or Missing[] to fill in for invalid outputs, which can then be handled by plotting functions. – J. M.'s missing motivation Oct 28 '15 at 15:55
  • Works actually. Mathematica just seems to fill the Missings with Nulls. – Peter Oct 28 '15 at 15:55
  • My point was that you might want to set valid to always output a list with six elements, and use something for filling in "invalid" values. – J. M.'s missing motivation Oct 28 '15 at 15:58
  • I am unclear on what you are trying to do, but would this work? values = Table[valid[g], {g, 0, 1, 0.01}]; ListPlot[values] – MarcoB Oct 28 '15 at 16:01
  • Ok, yeah, that might help, especially since i'll probably have to sort the points in a way so i can colourkey connected results... will do that, thanks. – Peter Oct 28 '15 at 16:01
  • @MarcoB That's good... Only half of a solution though. I'll try to work with that table, EDIT and put in the missing variables if necessary. – Peter Oct 28 '15 at 16:06
  • @Peter, I'm not sure to which missing variable you are referring. I think I am not fully understanding your problem. Maybe you could edit your question showing why the solution I proposed is only halfway there, and I might be able to provide the other half :-) – MarcoB Oct 28 '15 at 16:13
  • yeah, will try :) I'll have to think about an examplatory function for valid[g] though. By halfway I meant that I'll have to plot it, so a graphic with 2 to 6 values for each g on the x-axis will be produced. – Peter Oct 28 '15 at 16:14
  • Why not just pad out the output of valid with Missing[]? – J. M.'s missing motivation Oct 28 '15 at 16:46
  • how would you do that? – Peter Oct 28 '15 at 16:50
  • PadRight[list, 6, Missing[]] is one way. – J. M.'s missing motivation Oct 28 '15 at 17:15
  • awesome, thank you. PadRight. Never heard of it before. EDIT: aaaah I've got an idea. – Peter Oct 28 '15 at 17:19
  • I think that answered it... where do I mark the correct answer if the work was done in the comments? :) – Peter Oct 28 '15 at 17:31
  • If no one posts an answer, write one yourself based on what you gleaned from the comments. I'll add another approach all together is to keep your original form and define valid so it remembers its results valid[g_?NumericQ] := valid[g]=Table.. (DiscretePlot handles the "short" lists with just a warning if you do that ) – george2079 Oct 28 '15 at 18:58

1 Answers1

3

Update

As I now understand your question the function valid is sort of pseudo-code for the purpose of asking the question.

The output that you are dealing with is a ragged list that may have two, four or six elements.

Starting with the original valid we generate a ragged list.

valid[g_?NumericQ] := Table[g^(i/6), {i, If[g < 1.5, 2, If[g < 2, 4, 6]]}]

raggedList = Table[{g, valid[g]}, {g, 1, 3, 0.01}];

This operation is efficient and generates all of the required data but the data can't be directly plotted.

One can use Reap and Sow to efficiently gather the data to plot.

The code below is verbose and I am quite certain it could be made significantly shorter but for the purpose of communicating I like to start with something that is easy to follow.

Essentially what we are doing is gathering data so that we can use ListPlot directly on the output.

out =
 Flatten[
  Reap[
    Map[
     Function[element,
      Which[Length[element[[2]]] == 6,
       Sow[{element[[1]], element[[2, 1]]}, 1];
       Sow[{element[[1]], element[[2, 2]]}, 2];
       Sow[{element[[1]], element[[2, 3]]}, 3];
       Sow[{element[[1]], element[[2, 4]]}, 4];
       Sow[{element[[1]], element[[2, 5]]}, 5];
       Sow[{element[[1]], element[[2, 6]]}, 6];
       ,
       Length[element[[2]]] == 4,
       Sow[{element[[1]], element[[2, 1]]}, 1];
       Sow[{element[[1]], element[[2, 2]]}, 2];
       Sow[{element[[1]], element[[2, 3]]}, 3];
       Sow[{element[[1]], element[[2, 4]]}, 4];
       ,
       Length[element[[2]]] == 2,
       Sow[{element[[1]], element[[2, 1]]}, 1];
       Sow[{element[[1]], element[[2, 2]]}, 2]
       ]
      ],
     list
     ],
    {1, 2, 3, 4, 5, 6}][[2]],
  1]

out can be directly plotted with ListPlot

ListPlot[out, PlotRange -> {{1, 3.05}, {0.95, 3.2}}]

Mathematica graphics

Original

Your question is about efficiency.

Currently you get a good answer but are making more computations than are required.

valid is used to generate lists of length 2, 4 and 6 and then you make six DiscretePlots by extracting the first and second columns from all 201 lists, the third and fourth from lists 51 to 201 and the fifth and sixth from lists 101 to 201 and make a discrete plot of each.

For this specific problem you can write a modified valid that will only compute what is needed based upon the value of i in your table (1 thru 6).

valid2[i_] := DiscretePlot[g^(i/6.),
  {g, Which[i < 3, 1, i < 5, 1.5, True, 2], 3, 0.01}]

The trick here is to set the starting value for g to be dependent upon i.

Using this function we can plot all of the data in one fell swoop

Show[
 Map[valid2[#] &, Range[6]],
 PlotRange -> All
 ]

which produces

Mathematica graphics

Jack LaVigne
  • 14,462
  • 2
  • 25
  • 37
  • Thank you for your answer. Unfortunately, in the original problem i do not know the exact spot from when on 2, 4 or 6 values appear. Also changing the structure "valid" is not really an option, as it is based on this: http://mathematica.stackexchange.com/questions/275/updating-wagons-findallcrossings2d-function – Peter Oct 29 '15 at 11:46
  • @Peter - I have updated the answer to work with ragged lists with lengths that may be 2, 4 or 6 elements in length. – Jack LaVigne Oct 29 '15 at 19:06
  • Really awesome! I stumbled over Sow and Reap a while a go but never really got their purpose. Will work with that. Thank you very much! – Peter Oct 31 '15 at 09:00