Mips branch: testing equality - branch

I need to know how can I test the equality of two registers in MIPS without using branches?
I need to make a new instruction that does the same as the beq without using branches...
The Labeling part can be done easily by using the Jump instruction, but how can we check for equality ?
Thanks in advance

If you've got two numbers X and Y, and X - Y equals 0, then X and Y are equal.
So, for example, if the two values you want to compare are in $t0 and $t1:
# $t2 will be 0 if $t0 and $t1 are equal, and non-zero otherwise
subu $t2, $t0, $t1
If you want to normalize the result to either 0 (non-equal) or 1 (equal), you could expand the above with:
# Set $t2 to 1 if it's non-zero
sltu $t2, $zero, $t2
# Flip the lsb so that 0 becomes 1, and 1 becomes 0
xori $t2, $t2, 1

If you also want to avoid using slt/slti/sltu/sltui you will have to resort to bit-by-bit manipulation of instructions, using J-format most probably.
Otherwise computing the difference then doing sltu $(result), $0, $(difference) is the best alternative.

You can check that the first register isn't smaller than the second, and the second isn't smaller than the first, so it means they are equals...
slt $t0 $t1 $t2 #t0 is 0 if t1==t2 or t1>t2
slt $t0 $t2 $t1 #t0 is 0 if t1==t2 or t1<t2
so if $t0 has value 0, then they are equal else they are unequal

Related

Fitting a multivariable polynomial with inequality constraints on the polynomial

I have experimental scattered data (in green, in the picture) in a 2D domain (x,y), that I want to fit with a two-dimensional polynomial, such as:
f(x,y) = c0 + c1*x + c2*y + c3*x*y + c4 * x ** 2 * y ** 2
where c0, c1,... are the coefficients of the polynomial. On top of this, I have equality and inequality constraints:
f(x=0,y) = 0
f(x,y) > 0, for 0 < x < 90
How can I do this? Can I express my inequality in f(x,y), by inequalities in the c0, c1, c2,... coefficients?
I used scipy.optimize.minimize to minimize the least squares of ||Ax-B||, where Ax is the polynomial expression evaluated at the experimental points, x is the vector of the coefficients c0, c1, c2,... to be optimized, and B is my experimental data. I really need some guidance on how to apply the inequality constraint.
What I tried so far:
I was able to implement the equality constraint, manually simplifying f(x,y) and f(x=0,y)=0, by substitution, and reformulating ||Ax-B||, but I cannot do that for the inequality constraint. See the picture,
where f(x=0,y) = 0 is satisfied, but not f(x,y) > 0.
I tried using the constraints parameter, but I could only apply inequality constraints on the c0,c1,c2,... coefficients, instead of applying the constraint on the desired f(x,y).
I have read on Lagrange multipliers and non-linear programming but I'm still lost.
Two solutions:
With scipy.optimize.minimize the function to be minimized is some kind of chi^2, but additionally, it your constraints are not met, then it returns np.inf, which provides hard boundary.
Use Monte-Carlo Markov Chain method. There are many implementations in python.

Fast way to set diagonals of an (M x N x N) matrix? Einsum / n-dimensional fill_diagonal?

I'm trying to write fast, optimized code based on matrices, and have recently discovered einsum as a tool for achieving significant speed-up.
Is it possible to use this to set the diagonals of a multidimensional array efficiently, or can it only return data?
In my problem, I'm trying to set the diagonals for an array of square matrices (shape: M x N x N) by summing the columns in each square (N x N) matrix.
My current (slow, loop-based) solution is:
# Build dummy array
dimx = 2 # Dimension x (likely to be < 100)
dimy = 3 # Dimension y (likely to be between 2 and 10)
M = np.random.randint(low=1, high=9, size=[dimx, dimy, dimy])
# Blank the diagonals so we can see the intended effect
np.fill_diagonal(M[0], 0)
np.fill_diagonal(M[1], 0)
# Compute diagonals based on summing columns
diags = np.einsum('ijk->ik', M)
# Set the diagonal for each matrix
# THIS IS LOW. CAN IT BE IMPROVED?
for i in range(len(M)):
np.fill_diagonal(M[i], diags[i])
# Print result
M
Can this be improved at all please? It seems np.fill_diagonal doesn't accepted non-square matrices (hence forcing my loop based solution). Perhaps einsum can help here too?
One approach would be to reshape to 2D, set the columns at steps of ncols+1 with the diagonal values. Reshaping creates a view and as such allows us to directly access those diagonal positions. Thus, the implementation would be -
s0,s1,s2 = M.shape
M.reshape(s0,-1)[:,::s2+1] = diags
If you do np.source(np.fill_diagonal) you'll see that in the 2d case it uses a 'strided' approach
if a.ndim == 2:
step = a.shape[1] + 1
end = a.shape[1] * a.shape[1]
a.flat[:end:step] = val
#Divakar's solution applies this to your 3d case by 'flattening' on 2 dimensions.
You could sum the columns with M.sum(axis=1). Though I vaguely recall some timings that found that einsum was actually a bit faster. sum is a little more conventional.
Someone has has asked for an ability to expand dimensions in einsum, but I don't think that will happen.

How do I estimate the point of fracture of a curve in gnuplot

I want to estimate the point of fracture (x_F) (red circle) via ternary operator to restrict the range of my plot to it.
Example plot
To achieve a restriction to the X(Y_max)-value the stats command in combination with ternary-operator seems to be sufficient:
stats 'foo.csv' u 5 nooutput name 'Y_'
stats 'foo.csv' u 4 every ::Y_index_max::Y_index_max nooutput
X_max = STATS_max
plot 'foo.csv' u 4:(($4 <= X_max) ? $5 : 1/0) w l notitle
I cannot use the X_max-variable, because there a several points beyond the point of fracture (x_n > x_F) due to measurement errors. My idea was to compare the x-entries $4 to one another and to save the first point which satisfies $4_prev > $4_curr and to save it as x_F=$4_prev.
A simple delta-function seems to do the trick: delta(x)=(D=x-old_D,old_D=x,D) and old_D=NaN in combination with the ternary operator (delta($4)>0 ? $5 : 1/0) whereas $5 is the y-value, which will be plotted as long as the difference of two sequent x-values is positive.
You want to discard any data point after dx has become negative for the first time, right? You'll need a flag variable, i called it broken, which is set after the first occurrence of dx < 0:
broken = 0
plot dataf us (lastx=thisx, thisx=$4): \
(broken ? 1/0 :($4 < lastx) ? $5 : (broken=1, 1/0))
This uses the comma as "serial evaluator", same as in C, etc.
(Not tested now, as i don't have a suitable data set at hand and was too lazy to create one.)
Update: You can put the assignment broken=0 into the plot
plot broken=0, dataf us ....
, to be able to replot, zoom that plot etc.

what is the most efficient way to create a categorical variable based on another continuous variable in python pandas?

I have a continuous variable A (say, earnings) in my dataframe. I want to make a categorical variable B off that. Specifically, I'd like to define the second variable as going up in increments of 500 until a certain limit. For instance,
B= 1 if A<500
2 if A>=500 & A<1000
3 if A>=1000 & A<1500
....
11 if A>5000
What is the most efficient way to do this in Pandas? In STATA in which I mostly program, I would either use replace and if (tedious) or loop if I have many categories. I want to break out of STATA thinking when using Pandas but sometimes my imagination is limited.
Thanks in advance
If the intervals are regular and the values are positive as they seem to be in the example, you can get the integer part of the values divided by the length of the interval. Something like
df['category'] = (df.A / step_size).astype(int)
Note that if there are negative values you can run into problems, e.g. anything between -500 and 500 comes out as 0. But you can get around this by adding some base value before dividing. You can effectively define you're catgeories as the multiples of step size from some base value, which happens to be zero above.
Something like
df['category'] = ((df.A + base) / step_size).astype(int)
Here'a another approach for intervals which aren't regularly spaced:
lims = np.arange(500, 5500, 500)
df['category'] = 0
for lim in lims:
df.category += df.A > lim
This method is good when you have a relatively small number of limits but slows down for many, obviously.
Here's some benchmarking for the various methods:
a = np.random.rand(100000) * 6000
%timeit pd.cut(a, 11)
%timeit (a / 500).astype(int)
100 loops, best of 3: 6.47 ms per loop
1000 loops, best of 3: 1.12 ms per loop
%%timeit
x = 0
for lim in lims:
x += a > lim
100 loops, best of 3: 3.84 ms per loop
I put pd.cut in there as well as per John E's suggestion. This yields categorical variables rather than integers as he pointed out which have different uses. There are pros and cons to both approaches and the best method would depend on the scenario.

How to assign values randomly based on a percentage in SAS?

This question pertains to SAS. I need to generate a variable randomly, let's call it "species," for which 60% of the cases are 1's and the remaining 40% of cases are 0's. There are 15,000 cases of x_1 (where x_1 is a random, uniformly distributed variable) which need assignment of either 1 or 0. It's got to be generated with an if-then-do statement, right? So far, I have:
data species_list;
set work.species_list;
if x_1 <= 0.6 then do;
Species = 1;
end;
else if x_1 > 0.6 then do;
Species = 0;
end;
run;
This part is easy enough. But, I need the 1's and 0's to be randomly assigned to the 15,000 cases, not based on some inequality.
If x_1 is a random, uniformly distributed variable, then this inequality does distribute them 'randomly' (as much as can be done with a computer, anyway).
From what I recall, your inequality will work, more or less. It's not perfect; most likely your random number has a lower bound of 0 and an upper bound of 0.999999, so it's not quite going to give perfect 60/40 split, though with 15000 you probably will see a reasonably close match.
A somewhat better way is to use proc surveyselect. This doesn't require your x_1 variable.
proc surveyselect data=species_list out=species_out samprate=0.6 outall seed=12345;
run;
That would sample 60% and give them a 1, and the remaining 40% would be a 0. Easy as pie.
If you want to produce a random variable in SAS you can use the rand function.
You could use:
Species = ifn(rand("uniform") <= 0.6, 1, 0);
or:
x_1 = rand("uniform");
if x_1 <= 0.6 then Species = 1;
else Species = 0;
Depending on which one is more understandable to you.
rand(dist [, parameters]) produces a random number generated from one of several distributions.
ifn(condition, trueValue, falseValue) will return its second or third (numeric) argument depending on whether the condition evaluates to true or false.
It is not necessary to wrap your conditional statements in do; end; if you only want to run one statement.
If you want reproducable results you can provide a seed to the PRNG with call streaminit.