Message Boards Message Boards

0
|
1337 Views
|
23 Replies
|
4 Total Likes
View groups...
Share
Share this post:

Conditionals applied to choose one function rather than the other?

Hi, everyone! I am dealing with a problem that requires the use of conditionals applied to choose one function rather than the other, depending on the value assumed by a third function. For example, there are two functions F1[x,y] and F2[x,y], and also the third function G[y]. If G[y] is higher than a constant value (for instance 2000), F1[x,y] must be chosen; otherwise, F2[x,y] is used for computation. I wrote a code to do that, but unfortunately it didn't work out.

G[y_]:=10*y

F1[x_,y_]:=(x-x^2)*(1-2*x)+0.1*y^2*(1-2*x)/(x-x^2)^2 if G[y]>=2000

F2[x_,y_]:=(x-x^2)*(1-2*x)+5*y*(1-2*x)/(x-x^2)^2 if G[y]<2000

The aim is to choose F1[x,y] for computation if G[y]>=2000 or F2[x,y] if G[y]<2000. In fact, a generic function F[x,y] will become F1[x,y] or F2[x,y] depending on G[y]. Thus, F[x,y] is used for computation.

How can F[x,y] be written then?

I defined the function F[x,y] using the command Piecewise as a typical mathematical expression.

F[x,y] = F1[x,y] for G[y]>=2000 and F2[x,y]=F2[x,y] for G[y]<2000

Is this really the most appropriate command to do that? How is another way of doing this in Mathematica?

Thank you in advance for your response.

POSTED BY: Edson Orati
23 Replies
Posted 5 months ago
F1[x_,y_]:=x*y
F2[x_,y_]:=x/y
G[x_,y_]:=x-y
F[x_,y_]:=Which[G[x,y]>20,F1[x,y],G[x,y]<20,F2[x,y]]

Then

F[40,10]

returns 400 and

F[40,30]

returns

4/3
POSTED BY: Bill Nelson

Hi, Bill Nelson! I have just edited the problem making it more interesting. Sorry for that! I will see if your idea works out. Thank you.

POSTED BY: Edson Orati
Posted 5 months ago

You could use Condition:

G[y_] := 10*y;
F[x_, y_] := x^2 + y /; G[y] >= 2000
F[x_, y_] := -(x + y) /; G[y] < 2000

(I simplified the functions for clarity.)

F[1, 1]
(* -2 *)

F[1, 2000]
(* 2001 *)
POSTED BY: Eric Rimbey

Hi, Eric! I am having trouble with the command Transpose. There are two lists of different levels, e.g.

L1={a1,a2,a3}

and

L2={{b1,b2,b3},{c1,c2,c3}}

I want to obtain a list like that:

L3={{a1,b1},{a1,c1},{a2,b2},{a2,c2},{a3,b3},{a3,c3}}

What should I do? Please help me out. Thank you in advance for your help.

POSTED BY: Edson Orati
Posted 5 months ago

Transpose just restructures things, it won't actually change the contents of the things. In your case, you need to duplicate some of the elements (e.g. you want a1 to appear in both {a1,b1} and {a1,c1}).

But we can work up to what you want (there are probably several other ways to do this):

Transpose[L2]
(* {{b1, c1}, {b2, c2}, {b3, c3}} *)

That kinda looks like it's going in the right direction. We just want to somehow "thread" the as through these.

Thread[{L1, Transpose[L2]}]
(* {{a1, {b1, c1}}, {a2, {b2, c2}}, {a3, {b3, c3}}} *)

Still headed in the right direction. What if we thread each of the three sublists?

Thread /@ Thread[{L1, Transpose[L2]}]
(* {{{a1, b1}, {a1, c1}}, {{a2, b2}, {a2, c2}}, {{a3, b3}, {a3, c3}}} *)

That's very close. We just need to remove a layer of List:

Flatten[Thread /@ Thread[{L1, Transpose[L2]}], 1]
(* {{a1, b1}, {a1, c1}, {a2, b2}, {a2, c2}, {a3, b3}, {a3, c3}} *)

Bingo!

POSTED BY: Eric Rimbey

All this sequence of commands reveals that I must study more. By the way, you are extraordinary! Thank you once again.

POSTED BY: Edson Orati

Eric, to be honest, I haven't understood clearly the following step:

Thread /@ Thread[{L1, Transpose[L2]}]

The shorthand /@ refers to the command Map. How would you write this step without the shorthand? Thank you for your patience with me.

POSTED BY: Edson Orati
Posted 5 months ago
Map[Thread, Thread[{L1, Transpose[L2]}]]
POSTED BY: Eric Rimbey

Hi, Eric Rimbey! You are helping me a lot. Thank you. Can you help me again, please?

What if the result is like that:

{{{a1, {b1}}, {a1, {c1}}, {a2, {b2}}, {a2, {c2}}, {a3, {b3}}, {a3, {c3}}}

This is happening because L2 is like that:

L2={{{b1},{b2},{b3}},{{c1},{c2},{c3}}}

I realize that the command Flatten does not do what I want, which is that:

L2={{b1,b2,b3},{c1,c2,c3}} 

and also finally that

{{a1, b1}, {a1, c1}, {a2, b2}, {a2, c2}, {a3, b3}, {a3, c3}}

How would you deal with that?

Thank you in advance for your response and for your kind attention.

POSTED BY: Edson Orati

Hi,Eric! I managed to solve the problem.

L1={{a1,{b1}},{a1,{c1}},{a2,{b2}},{a2,{c2}}}

Using this command:

L1/.{a_,{b_}}:>{a,b}

Do you have another way to solve this?

In addition, I bumped into another problem, because I have two sets of points for each a, since c1>b1. How can I extract only the pairs {ai,c1} referring to the points with the maximum values of the cs.

I'm thinking how to do that. Can you help me, please? Thank you.

POSTED BY: Edson Orati
Posted 5 months ago
L1 = {a1, a2, a3};
L2 = {{{b1}, {b2}, {b3}}, {{c1}, {c2}, {c3}}};
Flatten[Map[Thread, Thread[{L1, Transpose[Flatten /@ L2]}]], 1]

This is getting a bit convoluted. There are probably better ways to manage your data structures elsewhere in your workflow.

POSTED BY: Eric Rimbey
Posted 5 months ago

Can you please start with a new question? I'm not understanding your latest question, and I think you're probably not providing all the context.

POSTED BY: Eric Rimbey

Hi, Eric! I have the following list:

L1={{a1,b1},{a1,c1},{a2,b2},{a2,c2}}

I want to take the pair {a1,c1} rather than {a1,b1}, because c1>b1.

In other words, the result should be two lists L2 and L3 like:

L2={{a1,b1},{a2,b2}}

and

L3={{a1,c1},(a2,c2}}

I believe I should define a function for that, shouldn't I?

Thank you in advance for your response.

POSTED BY: Edson Orati
Posted 5 months ago

This comment

I want to take the pair {a1,c1} rather than {a1,b1}, because c1>b1.

seems to contradict this comment

In other words, the result should be two lists L2 and L3 like:

You can't take one thing and end up with two things. Are you actually wanting to sort? Or maybe just group things a certain way?

POSTED BY: Eric Rimbey
Posted 5 months ago

I think maybe we've gotten too far away from your actual question. I suspect that you've tried to simplify your question, which is generally a good thing to do, but I fear we may be so far away from your actual need that you're doing a lot of unnecessary work.

To me, this is starting to sound like maybe you need some stronger structures to support some sort of analysis. Like, maybe you need associations. Starting with some dummy data and your data as pairs...

b1 = 5;
b2 = 10;
c1 = 7;
c2 = 14;
L1 = {{a1, c1}, {a1, b1}, {a2, b2}, {a2, c2}} (* I re-ordered so we can see how things change when we sort later *)

maybe we should add Association structure to it...

data1 = Merge[Rule @@@ L1, Identity]
(* <|a1 -> {7, 5}, a2 -> {10, 14}|> *)

Now you can do some queries or whatever. Since you're doing comparisons, you can sort this:

Sort /@ data1
(* <|a1 -> {5, 7}, a2 -> {10, 14}|> *)

Or if you knew you were going to need the data sorted, you could have done this when you created the association:

data2 = Merge[Rule @@@ L1, Sort]
(* <|a1 -> {5, 7}, a2 -> {10, 14}|> *)

Anyway, now we can split this data based on Min or Max:

Through[{Map[Min], Map[Max]}[data2]]
(* {<|a1 -> 5, a2 -> 10|>, <|a1 -> 7, a2 -> 14|>} *)

Anyway, this is all speculation. I don't really know how to answer your question, because it seems like it's missing important context.

POSTED BY: Eric Rimbey

Hi, Eric Rimbey! You are so knowledgeable that every post of yours is full of insights and impresses me. Well. I must apologize for my lack of clarity and for not defining the context. English is not my mother language and in fact I am not good at programming, but I am always thinking to improve my knowledge and this discussion forum has been an oasis. Recently, I am dealing with a Fluid Mechanics problem whose solution is a big set of data from a complex algebraic equation. Despite that, you must find easy to answer my question.To solve the problem, I wrote a code in Mathematica using SolveValues. The output is a set of data points like that:

{{0.95,0.001},{0.38,0.001},... and many other points of the type {number,0.001}
{{1.2,0.006},{0.52,0.006},... and many other points of the type {number,0.006}
{{0.76,0.011},{0.29,0.011},... and many other points of the type {number,0.011}

and so on. Note that each element of the list is a pair {x,y} where y is varying from 0.001 up to 1 in increments of 0.005. Therefore, I want to sort the elements in which x has the highest value for each value of y. Does it require association? Well, I haven't done the programming course about associations yet. As you notice, I am a newcomer. Anyway, I am thinking how to separate this list into two lists using Mathematica. If you can help me do that, I will be grateful to you once again. Maybe the command Max could be useful for that.

Also, I want to take this opportunity to ask you another question about the differences between Plot, ListLinePlot and ListPlot. Plot is used for a continuous domain of variables, while ListPlot is for discrete points. Usually, the solution of algebraic equations is sets of discrete points that must be sorted. For this reason, I cannot use Plot, but ListPlot for plotting. However, my plots are weird with only points. It is common to see solid continuous boundary lines in the literature. Then, I thought of ListLinePlot. However, the command ListLinePlot creates lines between points in such a way that the plot of points turns into a hatched region, messing up the plot. Honestly, I am really struggling with the use of these commands for what I want to produce. Sorry for being far away from the main question of this forum. Anyway, my questions might serve to someone. Overall, I am definitely learning a lot by using Mathematica and also from you. Thank you, really.

POSTED BY: Edson Orati
Posted 5 months ago

Here's some dummy data to make it easier to demonstrate (this would be just one set of results from SolveValues, i.e. the results where y=5):

data = {{72, 5}, {59, 5}, {38, 5}, {51, 5}, {55, 5}, {16, 5}, {93, 5}, {96, 5}, {67, 5}, {8, 5}}

To find the pair whose x value is largest:

MaximalBy[data, First]
(* {{96, 5}} *)

Notice that it's a list of pairs (just one pair in this case). That's because there may have been several pairs whose first element was the max.

I want to sort the elements in which x has the highest value for each value of y

Okay, if you want them sorted:

SortBy[data, First]
(* {{8, 5}, {16, 5}, {38, 5}, {51, 5}, {55, 5}, {59, 5}, {67, 5}, {72, 5}, {93, 5}, {96, 5}} *)

ReverseSortBy[data, First]
(* {{96, 5}, {93, 5}, {72, 5}, {67, 5}, {59, 5}, {55, 5}, {51, 5}, {38, 5}, {16, 5}, {8, 5}} *)

how to separate this list into two lists

Again, I don't understand this. What are the two lists you want?

POSTED BY: Eric Rimbey
Posted 5 months ago

For the plotting stuff, you need to provide concrete examples. I can't tell what the problem is just by your description.

POSTED BY: Eric Rimbey

Hi, Eric! I am sending you my notebook (attached) that contains two questions. To be honest, I have attempted many times to get what I want and your help can illuminate my work. Thank you in advance for your help.

Attachments:
POSTED BY: Edson Orati
Posted 5 months ago

I'll tackle your questions from your Example.nb one at a time in separate replies:

As you can see in the matrix from the previous command, there are pairs.08 {x,y} and x assumes low and high values for each y value. For instance, the first two elements have x=3.58297 and x=0.316068 for y=0.01 Question: How to separate this list into two lists where one has the highest values of x while the one list has the lowest values of x?

So, early on you created a table using some ranges. You threw away the range info. Then later on you tried to re-incorporate the range info. This is a very complicated workflow. So, I'd simplify the whole thing as follows.

Let's start here:

\[Delta]tRoots = Table[SolveValues[fjf\[Delta]t[jf, \[Delta]t] == 0, \[Delta]t, Reals], {jf, 0.001, 1, 0.1}];
\[Delta]tRootsF = Flatten[\[Delta]tRoots]
(* {0.0169133,0.211189,0.788811,0.983087,0.0978286,0.194265,0.805735,0.902171} *)

For clarity, I changed the range step so that we have shorter lists to look at. Next you define a range.

jfRange = Range[0.01, 1, 0.2]
(* {0.01, 0.21, 0.41, 0.61, 0.81} *)

I did a similar simplification. And now you get your main result.

jgRoots = 
  Table[
    SolveValues[fjfjg\[Delta]t[jf, jg, \[Delta]t] == 0, jg, Reals], {\[Delta]t, \[Delta]tRootsF}, 
    {jf, jfRange}]
(* {{{3.58297},{17.5798},{25.4253},{31.6752},{37.0623}},{{0.316068},{0.332205},{0.347738},{0.362734},{0.37725}},{{},{},{},{},{}},{{},{},{},{},{}},{{0.858419},{1.11999},{1.33969},{1.53368},{1.70974}},{{0.374548},{0.397487},{0.419413},{0.440458},{0.460727}},{{},{},{},{},{}},{{},{},{},{},{}}} *)

The next bunch of code in your notebook is trying to get the jfRange values assocated back in to these results. But you could have just done that to start. Here are a few ways.

jgRootsAlt1 = 
 Table[
    {jf, SolveValues[fjfjg\[Delta]t[jf, jg, \[Delta]t] == 0, jg, Reals]}, 
    {\[Delta]t, \[Delta]tRootsF}, 
    {jf, jfRange}]

(*
  {{{0.01,{3.58297}},{0.21,{17.5798}},{0.41,{25.4253}},{0.61,{31.6752}},{0.81,{37.0623}}},
   {{0.01,{0.316068}},{0.21,{0.332205}},{0.41,{0.347738}},{0.61,{0.362734}},{0.81,{0.37725}}},
   {{0.01,{}},{0.21,{}},{0.41,{}},{0.61,{}},{0.81,{}}},
   {{0.01,{}},{0.21,{}},{0.41,{}},{0.61,{}},{0.81,{}}},
   {{0.01,{0.858419}},{0.21,{1.11999}},{0.41,{1.33969}},{0.61,{1.53368}},{0.81,{1.70974}}},
   {{0.01,{0.374548}},{0.21,{0.397487}},{0.41,{0.419413}},{0.61,{0.440458}},{0.81,{0.460727}}},
   {{0.01,{}},{0.21,{}},{0.41,{}},{0.61,{}},{0.81,{}}},
   {{0.01,{}},{0.21,{}},{0.41,{}},{0.61,{}},{0.81,{}}}}     
*)

But with this, we'll need to use Transpose to get all the solutions for the same jfRange value together. We can avoid that by just changing the order of our iterators.

jgRootsAlt2 = 
 Table[
    {jf, SolveValues[fjfjg\[Delta]t[jf, jg, \[Delta]t] == 0, jg, Reals]}, 
    {jf, jfRange}, 
    {\[Delta]t, \[Delta]tRootsF}]
(*
  {{{0.01,{3.58297}},{0.01,{0.316068}},{0.01,{}},{0.01,{}},{0.01,{0.858419}},{0.01,{0.374548}},{0.01,{}},{0.01,{}}},
   {{0.21,{17.5798}},{0.21,{0.332205}},{0.21,{}},{0.21,{}},{0.21,{1.11999}},{0.21,{0.397487}},{0.21,{}},{0.21,{}}},
   {{0.41,{25.4253}},{0.41,{0.347738}},{0.41,{}},{0.41,{}},{0.41,{1.33969}},{0.41,{0.419413}},{0.41,{}},{0.41,{}}},
   {{0.61,{31.6752}},{0.61,{0.362734}},{0.61,{}},{0.61,{}},{0.61,{1.53368}},{0.61,{0.440458}},{0.61,{}},{0.61,{}}},
   {{0.81,{37.0623}},{0.81,{0.37725}},{0.81,{}},{0.81,{}},{0.81,{1.70974}},{0.81,{0.460727}},{0.81,{}},{0.81,{}}}}
*)

Now you want to collect these groups together and find minimums and maximums. You could do this with this structure, but there is built in functionality, Merge that will do all of that for us. To use Merge we need Rules. So, let's try yet again...

jgRootsAlt3 = 
 Table[
    jf -> SolveValues[fjfjg\[Delta]t[jf, jg, \[Delta]t] == 0, jg, Reals], 
    {jf, jfRange}, 
    {\[Delta]t, \[Delta]tRootsF}]
(*
  {{0.01->{3.58297},0.01->{0.316068},0.01->{},0.01->{},0.01->{0.858419},0.01->{0.374548},0.01->{},0.01->{}},
   {0.21->{17.5798},0.21->{0.332205},0.21->{},0.21->{},0.21->{1.11999},0.21->{0.397487},0.21->{},0.21->{}},
   {0.41->{25.4253},0.41->{0.347738},0.41->{},0.41->{},0.41->{1.33969},0.41->{0.419413},0.41->{},0.41->{}},
   {0.61->{31.6752},0.61->{0.362734},0.61->{},0.61->{},0.61->{1.53368},0.61->{0.440458},0.61->{},0.61->{}},
   {0.81->{37.0623},0.81->{0.37725},0.81->{},0.81->{},0.81->{1.70974},0.81->{0.460727},0.81->{},0.81->{}}}
*)

And now...

Merge[jgRootsAlt3, MinMax@*Flatten]
(* <|0.01->{0.316068,3.58297},0.21->{0.332205,17.5798},0.41->{0.347738,25.4253},0.61->{0.362734,31.6752},0.81->{0.37725,37.0623}|> *)

Okay, I probably need to explain MinMax@*Flatten. Merge let's you supply a function to apply to the list of elements that share a common key. Try a dummy function just to see how it works:

Merge[jgRootsAlt3, someFunction]
(*
<|0.01->someFunction[{{3.58297},{0.316068},{},{},{0.858419},{0.374548},{},{}}],
  ...etc...
  0.81->someFunction[{{37.0623},{0.37725},{},{},{1.70974},{0.460727},{},{}}]|>
*)

Well, we know we want to flatten things:

Merge[jgRootsAlt3, Flatten]
(*
<|0.01->{3.58297,0.316068,0.858419,0.374548},
 ....etc....
  0.81->{37.0623,0.37725,1.70974,0.460727}|>
*)

And now, we'd like to find minimums and maximums. You can apply functions over Associations directly, and fortunately, there is a built in function to do both Min and Max:

MinMax /@ Merge[jgRootsAlt3, Flatten]
(* <|0.01->{0.316068,3.58297},0.21->{0.332205,17.5798},0.41->{0.347738,25.4253},0.61->{0.362734,31.6752},0.81->{0.37725,37.0623}|> *)

And you could just use that. But I got fancy and just did the whole thing with Merge by using Composition. You can compose two functions into a single function that applies both in sequence. That's how I got to MinMax@*Flatten.

So, at this point, we have some data that's organized into what you want. It's not how you originally envisioned it, but it's semantically equivalent. With that data, we can move on to plotting:

minMaxData = Merge[jgRootsAlt3, MinMax@*Flatten]

(It may take me awhile to post the next answer about plotting...)

POSTED BY: Updating Name

Thank you very much! I cannot thank you enough.

I am learning a lot from discussions on the Wolfram community.

POSTED BY: Edson Orati

Hey, Eric! You are the most responsible for my progress in my scientific work and your act towards me is making me realize that my potential to do things can be limitless with the aid of Mathematica. Sincerely, I am going to make more efforts to improve my communication and programming skills. Thank you for your patience. Best regards, Edson.

POSTED BY: Edson Orati
Posted 5 months ago

Now for your plotting questions

How to produce vertical lines rather than a bunch of points like in the plot above?

&

Eric, the plot is really bad, since the aim is to produce vertical lines as the trend of data points suggests.

I'm guessing a bit at what you want. It seems like you want vertical lines rather than horizontal, and that's easy to do by just reversing the order of the coordinates. I see that you're trying variations of ListPlot and ListLinePlot, so I'm guessing that you want lines connecting the min & max values we already determined, and you probably want separate lines for each pair rather than connecting the whole series of data.

So, starting with where I left off before,

minMaxData = Merge[jgRootsAlt3, MinMax@*Flatten]
(* <|0.01->{0.316068,3.58297},0.21->{0.332205,17.5798},0.41->{0.347738,25.4253},0.61->{0.362734,31.6752},0.81->{0.37725,37.0623}|> *)

we now need to pair our x values, which are the keys of this association with each y value, which are the values of the association. An easy way is with KeyValueMap:

plotData = KeyValueMap[Thread@*List, minMaxData]
(* 
  {{{0.01,0.316068},{0.01,3.58297}},
   {{0.21,0.332205},{0.21,17.5798}},
   {{0.41,0.347738},{0.41,25.4253}},
   {{0.61,0.362734},{0.61,31.6752}},
   {{0.81,0.37725},{0.81,37.0623}}} 
*)

Now, most Plot functions can take multiple series of data (lists of lists), so we can actually just pass this directly to ListLinePlot and it'll create separate line plots for each pair.

ListLinePlot[plotData]

enter image description here

Now, you also tried some of the Log forms of these plots. Those should work exactly the same way, the output will just be scaled differently.

I'll stop there for now. Feel free to redirect if this isn't what you wanted. We can also tweak the display characteristics of the plots however you want.

POSTED BY: Eric Rimbey
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract