3
$\begingroup$

I have a discretized region $\mathscr{R}$ and two functions $x(u,v)$ and $y(u,v)$. I wish to find (numerically of course) the values of $(u,v)$ such that

$$ \begin{align} \left(x(u,v),y(u,v)\right)\in \mathscr{R} \end{align} $$

To make it clearer let me take the functions $ \left(\frac{1}{3} \left(u^2+v^2\right),\frac{1}{3} \left(u^2-v^2\right)\right)$ and a geographical region, with

   scaled = TransformedRegion[RegionResize[DiscretizeRegion[GeoGridPosition[Entity["Country","Portugal"]["Polygon"], "Mercator"]], 1/2], TranslationTransform[{9.5, -43.4}]]; 
   Show[ParametricPlot[{(u^2 + v^2)/3, (u^2 - v^2)/3}, {u, 0, 2}, {v, 0, 2}], scaled]

so I have the following, and the idea is to get the set of $(u,v)$s that produce the blue part.

enter image description here

My solution: Take sample points $\left(\left(x(u,v),y(u,v)\right),(u,v)\right)$ on a large $uv$ rectangle and then choose those where $\left(x(u,v),y(u,v)\right)\in \mathscr{R}$. Then those points should be approximated to and area using ConvexHull or something else:

enter image description here

I'm not however happy with the discretization. I'd be glad to see shorter strategies.

$\endgroup$
4
  • $\begingroup$ What form do you want the result to be in? Or, how do you want to use such a characterization? This seems like a 2-dimensional region of $u$'s and $v$'s you're looking for, right? $\endgroup$
    – thorimur
    Commented Jun 1, 2022 at 0:02
  • $\begingroup$ @thorimur True. I want a region in $(u,v)$. I actually found an approximate solution which consists in creating pairs $\{(x,y),(u,v)\}$ an applying a function that chooses $(u,v)$ whenever $(x,y)$ is in desired region, and throwing it otherwise. But the result is very time consuming and at the end I have to approximate the points to an area using ConvexHull which is not visually nice. $\endgroup$ Commented Jun 1, 2022 at 0:15
  • $\begingroup$ @thorimur edit added. $\endgroup$ Commented Jun 1, 2022 at 0:27
  • $\begingroup$ Hmm, have you tried playing with ImplicitRegion somehow? $\endgroup$
    – thorimur
    Commented Jun 1, 2022 at 0:34

2 Answers 2

1
$\begingroup$

Here's a fully generic way with ImplicitRegion.


First, we might want to simply use scaled, or we might instead want to convert to a BoundaryMeshRegion via

bscaled = BoundaryDiscretizeRegion[scaled]

(As we'll see, this seems to improve performance.)

Second, with surface being your function of $u$ and $v$, we might want to use ImplicitRegion[surface[u,v] \[Element] reg, {{u, 0, 2}, {v, 0, 2}}].

(There is also InverseTransformedRegion[$reg,f,n$] instead of ImplicitRegion, which gives the region $\{p \in \mathbb{R}^n \mid f(p) \in reg\}$—in other words, exactly what you want, minus the bounds restrictions! However, as we'll see, there are computational problems with this option.)

Finally, if we discretize the result, we might want to discretize it via DiscretizeRegion or via BoundaryDiscretizeRegion.

Though, that part might depend on your application: if you don't need to discretize the resulting region, don't. Discretization of these regions takes some time! You might be able to use the region numerically even without discretizing it. some functions will work directly (and numerically) with the returned InverseTransformedRegion or ImplicitRegion anyway, so you might not need to discretize at all. However, if you're going to be doing a lot of different things with it, and if those computations are a bit slow, you might get better performance overall by discretizing from the outset.


But if you do need to discretize the resulting region...

I wrote a test to time all the different combinations:

  • scaled vs. bscaled
  • ImplicitRegion vs. InverseTransformedRegion
  • DiscretizeRegion vs. BoundaryDiscretizeRegion.

The best was BoundaryDiscretizeRegion on an ImplicitRegion that referred to bscaled, which clocked in at around 44 seconds.

(* Best performance: *)

surface[u_, v_] := {(u^2 + v^2)/3, (u^2 - v^2)/3}

bscaled = BoundaryDiscretizeRegion[scaled];

BoundaryDiscretizeRegion[
  ImplicitRegion[surface[u, v] \[Element] bscaled,
                 {{u, 0, 2}, {v, 0, 2}}]
                        ]

The transformed region. Contrast with using scaled instead, which took almost 3 minutes. It performed about the same as using DiscretizeRegion on the outer level, but since BoundaryDiscretizeRegion seems to work better as an input, you might want to use BoundaryDiscretizeRegion anyway.

When I tried to discretize InverseTransformedRegion, it made my CPU temperature shoot up to 100ºC and wasn't any quicker. So if you're going to discretize it, I would recommend using ImplicitRegion instead of InverseTransformedRegion. However, there's always the chance that it will perform better with other operations; it all depends on how you'll be using this.

Maybe someone can suggest good option values for BoundaryDiscretizeRegion or DiscretizeRegion that would speed things up, or a tweak to this approach. I do think that an approach like this at least has the advantage of giving you "the right kind of thing" as a result—namely, a region. But I'm sure there are improvements that can be made.


For reference, here's the test I used. I wound up evaluating some individually when I wanted to skip some. I don't recommend running the test.

ClearAll[scaled, bscaled, method, reg, surface, uvImplicit, uvInverseTransformed, inputregiontype]

scaled = 
  TransformedRegion[
   RegionResize[
    DiscretizeRegion[
     GeoGridPosition[Entity["Country", "Portugal"]["Polygon"], 
      "Mercator"]], 1/2], TranslationTransform[{9.5, -43.4}]];

bscaled = BoundaryDiscretizeRegion[scaled];

surface[u_, v_] := {(u^2 + v^2)/3, (u^2 - v^2)/3}

(* Example of both methods, here using bscaled *)

uvImplicit = ImplicitRegion[surface[u, v] \[Element] bscaled, {{u, 0, 2}, {v, 0, 2}}]

uvInverseTransformed = InverseTransformedRegion[bscaled, surface, 2]

(* Discretization test: *)

method["Implicit"] = ImplicitRegion[surface[u, v] \[Element] #1, {{u, 0, 2}, {v, 0, 2}}] &;
method["InverseTransformed"] = InverseTransformedRegion[#1, surface, 2] &;

inputregiontype["Mesh"] = scaled;
inputregiontype["BoundaryMesh"] = bscaled;

Table[
 Echo@AbsoluteTiming[{ (* Label: *) {disc, m, reg}, 
                       (* Output: *) disc[method[m][inputregiontype[reg]]]}
                     ],
 {m,    {"Implicit", "InverseTransformed"}}
 {disc, {DiscretizeRegion, BoundaryDiscretizeRegion}},
 {reg,  {"Mesh", "BoundaryMesh"}}
]
$\endgroup$
3
  • $\begingroup$ For some reason ImplicitRegion stops working when the functions are not elementary functions. But for simple choices it works well. Thank you. $\endgroup$ Commented Jun 5, 2022 at 17:26
  • $\begingroup$ @DanielCastro Interesting. I wonder if there's a workaround. Do you have an example of a nonelementary function I could try to get working? $\endgroup$
    – thorimur
    Commented Jun 5, 2022 at 22:23
  • $\begingroup$ Yes, for instance the field written in this question mathematica.stackexchange.com/questions/268865/… $\endgroup$ Commented Jun 5, 2022 at 22:37
4
$\begingroup$

Some thing like this?

xs[u_, v_] = (u^2 + v^2)/3;
ys[u_, v_] = (u^2 - v^2)/3;
sol = Solve[{x == xs[u, v], y == ys[u, v]}, {u, v}]
ParametricPlot[{u, v} /. sol[[4]], {x, y} ∈ scaled, 
 Frame -> False]

enter image description here

$\endgroup$
2
  • $\begingroup$ Thank you. It's a simple approach but it has the disadvantage that if the functions are not simple enough Solve will not work. $\endgroup$ Commented Jun 1, 2022 at 14:06
  • $\begingroup$ I would like something completely numerical so that no matter how complicated $x_s(u,v)$ and $y_s(u,v)$ are I will always get a solution. $\endgroup$ Commented Jun 1, 2022 at 14:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.