Plotting in maple - maple

I'm having trouble plotting a set of complex numbers in maple.
I know what it should look like from a drawing I produced but I'd like to plot it in maple. My code is as follows;
z := x + I*y;
plots:-implicitplot([abs(z) <= 2, abs(z) >= 1, abs(arg(z)) >= Pi/4,
abs(arg(z)) <= Pi/2], x = -3...3, y = -3...3, filled = true);
The issue is that the inequalities are being plotted independently of each other rather than all together, so even the first pair of inequalities together fill the entire plane. Is there any way I can have the $4$ conditions imposed in $S$ be taken into account at the same time, rather than separately?

Didn't you mean for the second inequality to be reversed? Otherwise the first is redundant.
The command that you need is inequal, not implicitplot. Your args should be arguments. Your z expressions should be wrapped in evalc. (I don't why that's necessary, but it seems to be.) There's no need for filled= true. So, the command is
plots:-inequal(
[evalc(abs(z)) <= 2, evalc(abs(z)) >= 1,
evalc(abs(argument(z))) >= Pi/4, evalc(abs(argument(z))) <= Pi/2
], x = -3...3, y = -3...3
);

Sometimes using plots:-inequal takes a long time, in those cases I just use plots:-implicitplot with filledregions = true option. But I don't use a list of inequalities as its argument. For one plot only, implicitplot needs one equation/inequality, so what function can you use that gives you the intersection of regions for your inequalities? Very simple, just define a binary piecewise function with piecewise command. Here is how I do your plot.
f := piecewise( And( abs( x + y*I ) <= 2, abs( x + y*I ) >= 1, abs( argument( x + y*I ) ) >= Pi/4, abs( argument( x + y*I ) ) <= Pi/2 ), 1, 0 );
plots:-implicitplot( f > 1/2, x = -3..3, y = -3..3, filledregions = true, coloring = [yellow, white], view = [-3..3, -3..3] );
The output plot is the following.
Note that plots:-inequal gives a more accurate output, but plots:-implicitplot takes less time, so you should consider the trade-off between them and see which is better on your specific example.

Related

How do I splice two vectors in MATLAB?

I need to splice two vectors based on a condition that also takes a vector as an argument. Example:
vec_cond = -5:5; % The exact values are calculated differently
vec1 = 0:10;
vec2 = 5:15;
I need a resulting vector to be comprised from values out of both vectors based on a condition from the third vector. Let's assume this is the condition: vec_cond >= 0
Then if this is true, I want vec_result to have values from vec1 on appropriate indexes, and if not, take values from vec2 on appropriate indexes:
vec_result = vec1 if (vec_cond >=0) else vec2
This is portion of my MATLAB script (original comments were Czech) where I would need to use that:
%% Draw output current and voltage characteristics
R = 100:5:2*10^3; % Load rezistor [ohm]
U_2 = R .* (I * 10^(-3)); % Load voltage [V]
U_1stab = U_LM + U_x + U_2; % Min. required input voltage
% for stabilization [V]
U_delta = U_1 - U_1stab; % Difference between actual and
% min. req. input voltage [V]
U_2norm = U_1 - U_LM - U_x % Calculating output load
% voltage based on params [V]
I_z = U_2norm ./ R .* 10^3; % Load current param based[mA]
I_r1 = I * I_z.^0; % Stabilizator current [mA]
So the condition would be U_delta >= 0.
I tried to use a ternary operator, which I found here:
I_graph = (U_delta >= 0) : (#() I) : (#() I_z); % Current splice [mA]
U_graph = (U_delta >= 0) : (#() U_2) : (#() U_2norm); % Voltage splice [V]
That means that for I_graph, if the condition is met, take a constant value I and vectorize it, otherwise take values from I_z vector. For U_graph, if the condition is met, take values from U_2 vector, otherwise take constant value of U_2norm and vectorize it.
But it didn't work, this is what it tells me:
Operator ':' is not supported for operands of type 'function_handle'.
Error in vypocet1 (line 52)
I_graph = (U_delta >= 0) : (#() I) : (#() I_z); % Current splice [mA]
I guess that I might want to use for loop, but I'm not sure how it will help me and how can I actually construct the necessary vector using a for loop.
Given:
vec_cond = -5:5;
vec1 = 0:10;
vec2 = 5:15;
You can set:
out = vec2;
I = vec_cond >= 0;
out(I) = vec1(I);
This uses logical indexing, which is indexing with a logical array.
By the way, the ternary operator you found is an exercise to overload the : operator for a specific class to do something that it normally doesn’t do. Note how you use the colon when creating vec_cond. This is what the colon operator does normally.

How to read a table in matlab, find the y values corresponding to x

I want to use the y value corresponding to the given x value from the table (my current table has 1000 values with 10-4 decimal points so I use :
load question_table.mat
eta_p = %assign a value
F12_p=find( (eta <eta_p+0.01) & (eta > eta_p-0.01), 1, 'first' )
what is missing ?
Here is how I have created the table, run this program.
i = 1;
etaspan = -500:0.001:500;
y = zeros(length(etaspan),1);
f = #(x,eta) (x.^(1/2))./(1+exp(x-eta));
for eta = etaspan
g = #(x) f(x,eta);
y(i) = integral(g,0,500);
i = i + 1;
end
f=y
eta=etaspan
save question_table.mat eta f
Just have MATLAB do the interpolation for you:
y_p = interp1(eta, y, eta_p);
interp1 uses linear interpolation by default, but can instead use higher order interpolation methods. Even with linear, your table seems much denser than necessary.

Matlab: How to assign values selectively to a matrix

I have 3 matrices x, y and z of order 3*3. I want to create a new matrix k with value = 1./(x.^2+y.^2+z.^2) if (x.^2+y.^2+z.^2 > 1) and value = 0 otherwise.
I am trying to use this :
k(x.^2+y.^2+z.^2>1)= 1./(x.^2+y.^2+z.^2)
but it gives error : In an assignment A(I) = B, the number of elements in B and I must be the same.
Can anyone provide a simple solution in a single line where I don't need to use for loops
I am not sure why you'd want to do this as opposed to splitting it up into two operations. This way, you save the cost of computing the sum of squares twice.
x = rand(3,3);
y = rand(3,3);
z = rand(3,3);
k = 1./(x.^2+y.^2+z.^2);
k(k>1)=0;
In any case, another way to do it would be using principles of Functional Programming:
x = rand(3,3);
y = rand(3,3);
z = rand(3,3);
myfun = #(x,y,z) 1/(x^2+y^2+z^2) * (x^2+y^2+z^2>1);
k = arrayfun(myfun, x, y, z);
Alternately, you can mix everything into one line as:
k = arrayfun(#(x,y,z) 1/(x^2+y^2+z^2) * (x^2+y^2+z^2>1), x, y, z);
What this code does is maps the function myfun to each of the data elements. The function myfun is quite simple. It computes the required quantity but multiplies it with the binding condition. However, you might want to beware.
EDIT: To address the comment.
If you don't want to compute the quantity at all, we can use conditional anonymous functions. For more details, you can refer to this guide.
iif = #(varargin) varargin{2 * find([varargin{1:2:end}], 1, 'first')}();
myfun = #(x,y,z) iif( x^2+y^2+z^2 <= 1, #() 0, x^2+y^2+z^2>1 ,#() 1/(x^2+y^2+z^2));
k = arrayfun(myfun, x, y, z);
How about
k = x.^2+y.^2+z.^2;
k(k < 1) = 0;
k(k~= 0) = 1 ./ k(k~=0);
If you are trying to save some processing time (i.e. do not compute at all the sum of squares for those cases when it is less than one) then pretty much the only solution is a table lookup
Otherwise the following code should work
k=1./(x.^2+y.^2+z.^2)
k(k<=1)=0
you can cut some time (assuming x, y and z could be greater than 1)
idx0=x<1 & y<1 & z<1
k=zeros(3)
k(idx0)=1./(x(idx0).^2+y(idx0).^2+z(idx0)^2)
k(k<=1)=0
Your original solution will work if you change it to use an indexer (I haven't profiled it, but I am pretty sure it will take longer, than mine :) )
idx0=x.^2+y.^2+z.^2>1
k=zeros(3)
k(idx0)=1./(x(idx0).^2+y(idx0).^2+z(idx0)^2)

Matlab: conv(u,v) but that sums 'u' and 'v'?

Is there any function in Matlab like conv(u,v) but that sums up 'u(x)' and 'v(x)' instead of multiplying them?
Imagine:
u(x) = 66*(x-6)
v(x) = 6*(x-9)
Applying this "wanted function"...
sum = wantedfunction(u,v)
So,
sum(x) = 66*(x-6) + 6*(x-9)
Any ideas?
I believe you can do what you are asking for using anonymous functions:
u = #( x ) ( 66 * (x - 6) );
v = #( x ) ( 6 * (x - 9) );
w = #( x ) ( u(x) + v(x) );
This makes w the "sum" function you wanted - if I understood your question correctly.
Example: after I keyed in the above, I found
w(1:5)
Gave
-378 -306 -234 -162 -90
It's possible I completely missed the point of your question - if so, please leave a comment.
If by "conv" function you mean convolution then the equivalent of that for your case is simply adding two functions you want and then multiply them by delta(your desired spacing on x axis) and then sum over that, gives your function. Still you need to iterate this process by a "for" loop for different delays.

Removing duplicate entries in a vector, when entries are complex and rounding errors are causing problems

I want to remove duplicate entries from a vector on Matlab. The problem I'm having is that rounding errors are stopping the inbuilt Matlab function 'unique' from working properly. Ideally I'd like a way to set some sort of tolerance on the 'unique' function, or a small procedure that will remove the duplicates otherwise. If both the real and imaginary parts of two entries differ by less than 0.0001, then I'm happy to consider them equal. How can I do this?
Any help will be greatly appreciated. Thanks
A simple approximation would be to round the numbers and the use the indices returned by unique:
X = ... (input vector)
[b, i] = unique(round(X / (tolerance * (1 + i))));
output = X(i);
(you can probably replace b with ~ depending on your Matlab version).
it won't quite have the behaviour you want, since it is possible that two numbers are very close but will be rounded differently. I think you could mitigate this by doing:
X = ... (input vector)
[b, ind] = unique(round(X / (tolerance * (1 + i))));
X = X(ind);
[b, ind] = unique(round(X / (tolerance * (1 + i)) + 0.5 * (1 + i)));
X = X(ind);
This will round them twice, so any numbers that are exactly on a rounding boundary will be caught by the second unique.
There is still some messiness in this - some numbers will be affected as though the tolerance was doubled. But it might be sufficient for your needs.
The alternative is probably a for loop:
X = sort(X);
last = X(1);
indices = ones(numel(X), 1);
for j=2:numel(X)
if X(j) > last + tolerance * (1 + i)
last = X(j) + tolerance * (1 + i) / 2;
else
indices(j) = 0;
end
end
X = X(logical(indices));
I think this has the best behaviour you can expect (because you want to represent the vector by as few unique values as possible - when there are lots of numbers that differ by less than the tolerance level, there may be multiple ways of splitting them. This algorithm does so greedily, starting with the smallest).
I'm almost certain the below ill always assume any values closer than 1e-8 are equal. Simply replace 1e-8 with whatever value you want.
% unique function that assumes 1e-8 is equal
function [out, I] = unique(input, first_last)
threshold = 1e-8;
if nargin < 2
first_last = 'last';
end
[out, I] = sort(input);
db = diff(out);
k = find(abs(db) < threshold);
if strcmpi(first_last, 'last')
k2 = min(I(k), I(k+1));
elseif strcmpi(first_last, 'first')
k2 = max(I(k), I(k+1));
else
error('unknown flag option for unique, must be first or last');
end
k3 = true(1, length(input));
k3(k2) = false;
out = out(k3(I));
I = I(k3(I));
end
The following might serve your purposes. Given X, an array of complex doubles, it sorts them, then checks whether the absolute value differences between elements is within the complex tolerance, real_tol and imag_tol. It removes elements that satisfy this tolerance.
function X_unique = unique_complex_with_tolerance(X,real_tol,imag_tol)
X_sorted = sort(X); %Sorts by magnitude first, then imaginary part.
dX_sorted = diff(X_sorted);
dX_sorted_real = real(dX_sorted);
dX_sorted_imag = imag(dX_sorted);
remove_idx = (abs(dX_sorted_real)<real_tol) & (abs(dX_sorted_imag)<imag_tol);
X_unique = X_sorted;
X_unique(remove_idx) = [];
return
Note that this code will remove all elements which satisfy this difference tolerance. For example, if X = [1+i,2+2i,3+3i,4+4i], real_tol = 1.1, imag_tol = 1.1, then this function will return only one element, X_unique = [4+4i], even though you might consider, for example, X_unique = [1+i,4+4i] to also be a valid answer.