Excel - Determine Parity of Permutation - excel

I am working on an Excel sheet where I need to determine the parity of a vertical array of numbers of size N. The array contains each number from 1 to N exactly one time each.
In this context, parity is defined as how many swaps is necessary to convert the scrambled array to a sorted array from smallest to largest.
For example, the array {3;1;2;4} has even parity because it would require two swaps (at minimum) to convert to {1;2;3;4}, but would always require an even number of swaps. See below.
3 --> 1 1
1 --> 3 --> 2
2 2 --> 3
4 4 4
Another example: {2;1;4;5;3} has odd parity because it would require three swaps (at minimum) to convert to {1;2;3;4;5}, but would always require an odd number of swaps. See below.
2 --> 1 1 1
1 --> 2 2 2
4 4 --> 3 3
5 5 5 --> 4
3 3 --> 4 --> 5
I am looking for a solution that would return TRUE for arrays with even parity and FALSE for arrays with odd parity. (And I don't care what the result is for arrays that do not contain all numbers from 1 to N because I have other checks in the spreadsheet to handle those cases.)
I have figured out a solution that uses several helper columns, but it seems like a sluggish calculation.
I do this by checking if each individual number in the array is in the correct index and, if it isn't perform a swap. I then sum up the amount of swaps that occurred and use MOD(<swaps>,2)=0 to determine if it is even parity.
See below for an example calculation with the array {8;5;3;2;4;1;7;6}.
I've color coded the cells to easily tell what is happening:
White = reference array {1;2;3;4;5;6;7;8}
Blue = input array
Grey = "helper" arrays where each successive column performs a swap if necessary
Red = Indicates if a swap occurred from previous column
Green = 1 if swap occurred in that column, and 0 if a swap didn't occur
Yellow = Sum of all green cells, effectively telling how many swaps occurred.
In this example, since the yellow cell is 4, which is an even number, the input array has even parity.
The question is: Can this calculation be done more efficiently in Excel without VBA? I'm not necessarily against helper columns, but again it just seems that my solution is sluggish and I'm wondering if there is a better way.

I think I have a way of doing this without the helper columns!
First, I'll show you a way with N helper columns and then I'll show how to use array formulas instead. Consider the matrix show below:
The green ranges are the indices and the blue range is your permutation. The yellow matrix is your permutation matrix defined as seen in the formula box.
The parity of your permutation is the same as the value of the determinant of this matrix!
Luckily, Excel has a built-in determinant function MDETERM(). An even permutation has parity 1 and an odd permutation has parity -1, so you can get the determinant simply with the formula
=MDETERM(C2:J9)
Now this is pretty cool, but the real kicker is that we don't even need to make that matrix. We can construct it in an array formula like this instead:
{=MDETERM(IF(B2:B9=TRANSPOSE(A2:A9),1,0))}
Here we only use columns A and B! Columns C:J are unused in this version.
(Note that this is an array formula so you will need to use Ctrl+Shift+Enter to validate it. This will wrap the braces around the formula. Don't do that manually.)

Related

How to find out Max<List<List>> in Excel?

I'd like to find out largest sum of numbers separated by empty row. In this example I am looking to get number 6 (3+3)
1
1
2
2
3
3
Brute forcing this I would =MAX(SUM(A1:A2),SUM(A4:A5),SUM(A7:A8)) which does the job but obviously not practical. How can I express above more elegantly without hardcoding anything?
Thinking out loud, I would like to
Ingest all numbers, split by empty row into some kind of List<List>
Iterate over this list, sum numbers in child list and pick a winner
How can this be done in Excel?
There are multiple ways of doing it, this is just one of them. In cell C1 you can put the following formula:
=LET(set, A1:A9, matrix, 1*TEXTSPLIT(SUBSTITUTE(TEXTJOIN(",",
FALSE, set),",,",";"),",",";", TRUE),m, COLUMNS(matrix), ones, SEQUENCE(m,1,,0),
MAX(MMULT(matrix, ones))
)
and here is the output:
Note: The third input argument of TEXTSPLIT set to TRUE ensures you can have more than one empty row in the middle of the range. The second input argument of TEXTJOIN set to FALSE is required to ensure to generate of more than one comma (,), which is our condition to replace by the row delimiter (;) so we can split by row and columns. MMULT requires numbers and TEXTSPLIT converts the information into texts. we need to coerce the result into a number by multiplying it by 1.
The formula follows the approach you suggested, you can test the intermediate step. Instead of having as output MAX result the variable you want to verify, for example:
=LET(set, A1:A9, matrix, 1*TEXTSPLIT(SUBSTITUTE(TEXTJOIN(",",
FALSE, set),",,",";"),",",";", TRUE),m, COLUMNS(matrix), ones, SEQUENCE(m,1,,0),
TMP, MAX(MMULT(matrix, ones)), matrix
)
will produce the following output:
1 1
2 2
3 3
An alternative to MULT is to use BYROW array function (less verbose):
=LET(set, A1:A8, matrix, 1*TEXTSPLIT(SUBSTITUTE(TEXTJOIN(",",
FALSE, set),",,",";"),",",";", TRUE),MAX(BYROW(matrix, LAMBDA(m, SUM(m))))
)

Excel: How to find closest number in table, many times

Excel
Need to find nearest float in a table, for each integer 0..99
https://www.excel-easy.com/examples/closest-match.html explains a great technique for finding the CLOSEST number from an array to a constant cell.
I need to perform this for many values (specifically, find nearest to a vertical list of integers 0..99 from within a list of floats).
Array formulas don't allow the compare-to value (integers) to change as we move down the list of integers, it treats it like a constant location.
I tried Tables, referring to the integers (works) but the formula from the above web site requires an Array operation (F2, control shift Enter), which are not permitted in Tables. Correction: You can enter the formula, control-enter the array function for one cell, copy the formulas, then insert table. Don't change the search cell reference!
Update:
I can still use array operations, but I manually have to copy the desired function into each 100 target cells. No biggie.
Fixed typo in formula. See end of question for details about "perfection".
Example code:
AI4=some integer
AJ4=MATCH(MIN(ABS(Table[float_column]-AI4)), ABS(Table[float_column]-AI4), 0)
repeat for subsequent integers in AI5...AI103
Example data:
0.1 <= matches 0
0.5
0.95 <= matches 1
1.51 <= matches 2
2.89
Consider the case where target=5, and 4.5, 5.5 exist in the list. One gives -0.5 and the other +0.5. Searching for ABS(-.5) will give the first one. Either one is decent, unless your data is non-monotonic.
This still needs a better solution.
Thanks in advance!
I had another problem, which pushed to a better solution.
Specifically, since the Y values for the X that I am interested in can be at varying distances in X, I will interpolate X between the X point before and after. Ie search for less than or equal, also greater than or equal, interpolate the desired X, then interpolate the Y values.
I could go a step further and interpolate N - 1 to N + 1, which will give cleaner results for noisy data.

How certain arrays and array functions are handled under the hood in Excel; specifically the dependence of array handling on the calling function

In trying to systematically enumerate the possibilities when rolling four identical but loaded four-sided dice, I came across some unusual excel behavior. Hoping someone can shed some light on what's going on under the hood.
The following table illustrates the possible rolls of a die:
1000 A
0100 B
0010 C
0001 D
each row is a possibility with a distinct probability. In excel, this information can be made to occupy a 4x4 cell area--that is, the letter labels above are merely for convenience.
In trying to display all possible combinations of four rolls of such a die-- where the fist combination might be A + A + A + A or 4000, the second might be B + A + A + A or 3100, and so on for each of the 4^4=256 possibilities--I decided that I wanted to systematically offset A by 0,1,2, or 3 rows for each of four rolls then sum the results. In other words, each possible group of 4 roles can be thought of as 4 copies of row A, each of which offset by some number of rows between 0 and 3, for example {0;0;0;0} or {1;0;0;0} in the first and second case enumerated directly above.
Oddly, though, I get the following. (all formulas are array formulas keyed in with shift+ctrl+enter).
=TRANSPOSE( SUM( OFFSET( A, 4x1ArrayOfRowOffsets, 0)))
displays the correct sum when entered into a 1x4 range. Likewise if =TRANSPOSE(...) is replaced by =INDEX(...,1,1). I take it because both functions natively support array arguments. However,
=SUM( OFFSET( A, 4x1ArrayOfRowOffsets, 0))
does not work--it seems that here the summation is conducted along the 4 rows returned by offset, each of which has value 1--it incorrectly displays only the value 1, even when evaluated in a multicell range as an array formula. Oddly,
=SUM( TRANSPOSE( OFFSET( A, 4x1ArrayOfRowOffsets, 0)))
does not work either--the transpose makes it so the summation is properly conducted along the columns returned by offset, but seems to throw out all but the first column.
Please note that, although the problem statement does not involve VBA, the lack of transparent array formula auditing in Excel proper (intermediate steps return #VALUE errors even when the final answer computes) likely means that, in order to investigate this problem, someone will have to write a bit of VBA that calls worksheet functions and manually outputs the intermediate calculations. This is why I posed a version of this question, here.
Interweaving INDEX calls anywhere but the outside/first function call does not fix the problem.
To try and see what is going on, I investigated further.
=INDEX( OFFSET( A, {w;x;y;z}, 0), 1, {1,2,3,4})
correctly displays the four rolls when entered into a 4x4 range. As before w, x, y, and z are integers between 0 and 3 indicating row offsets from "A" in the table, above. Furthermore,
=COLUMNS( OFFSET( A, {w;x;y;z}, 0))
returns the following when entered into a 5x5 range:
4 4 4 4 4
4 4 4 4 4
4 4 4 4 4
4 4 4 4 4
n/a n/a n/a n/a
All that is to say, calling SUM(OFFSET(---)) with array arguments seems to produce varied output depending on what is doing the calling--specifically, whether or not the caller is a function which natively accepts proper array arguments. Why is this? What is actually going on, here?

Sum rows (or columns) of a 2d matrix into a 1d array in an Excel formula

Is there any way to tell specify to Excel that it should perform a per-row calculation within a 2d matrix? For instance, if I have an array defined
{1,0,0;0,0,1;1,0,1}
i.e.
1 0 0
0 0 1
1 0 1
Is there a formula that can allow me to operate on the array {1;1;2}?
The eventual goal in this would most likely to be to further transform that array using an expression such as {1;1;2}>=2 or MATCH(2,{1;1;2},0), but the important thing isn't so much what the outer expression is as that the transformation takes place at all.
Of course, much of this can in many cases be outsourced to operations on a helper column, but there are numerous times when solving a problem with space feels like an inelegant approach.
MMULT would do what you wants.
{=MMULT({1,0,0;0,0,1;1,0,1},{1;1;1})}
used as array formula (CSE) results in {1;1;2}.
1,0,0 1 1*1+0*1+0*1 = 1
0,0,1 x 1 = 0*1+0*1+1*1 = 1
1,0,1 1 1*1+0*1+1*1 = 2
When MMULT is wrapped in other functions which take their parameters as arrays, there may not be the need for pressing Ctrl+Shift+Enter. For example
=MATCH(2,MMULT({1,0,0;0,0,1;1,0,1},{1;1;1}),0)
results in 3 without entering the formula using Ctrl+Shift+Enter.

Excel solver 5x5 sum game

My son found this math game app and I've been playing it. Essentially you have a 5x5 grid of numbers from 0-9, and then at the end of each column and row is a target sum. Every number in the grid can be turned on or off, and when the correct sum is achieved that row or column is highlighted. You can actually play on harder levels, but for an excel problem I decided to try 5x5 just to see if I could get solver to find the answer.
The way I designed this is as follows:
(a) Cells B2-F6 have the number values from the grid.
(b) Cells H2-L6 I put in all zeroes.
(c) Cells N2-S6 I put in as the product of B2 and H2, B3 and H3, etc.
(d) Cells N8-R8 are the sum of N2-N6, O2-O6, etc.
(e) Cells S2-S6 are the sums of N2-R2, N3-R3, etc.
(f) Cells N9-R9 are the target identified by the game.
(g) Cells N10-R10 are N9-N8, O9-O8, etc.
(h) Cells T2-T6 are the target identified by the game.
(i) Cells U2-U6 are T2-S2, T3-S3, etc.
(j) Cell W2 is =MAX(T2:T6,N9:R9)
(k) Cell T12 is =N10*W2^9+O10*W2^8+P10*W2^7+Q10*W2^6+R10*W2^5+U2*W2^4+U3*W2^3+U4*W2^2+U5*W2^1+U6*W2^0
In solver, I set the object of $T$12 to be value of 0, with constraints on variable cells $H$2:$L$6 as <=1, >=0, integer.
However, I can't seem to get solver to find me a solution. I solved it in the game first so I had a solution. When I put that in, solver will tell me it found a solution after changing nothing, or on the evolutionary one it will tell me it hasn't found anything better...of course not, I've already given you the solution. But if you change just one of the 5x5 grid to be wrong, it still can't find a solution. Is this just too complex for solver? It's weird to me that when it fails it has non-integer values in the cells. I keep wondering why it's trying non-integer values when I told it not to (and I did check to be sure my Ignore Integer Constraints box is unchecked). I understand that there are 2^25 different possibilities it should have to try, but there's an infinite number more (okay, maybe finite if it has a maximum number of decimals in the data type, but for all practical, non-quantum purposes, it's infinite) if it ignores my integer requirements. Maybe it's just not comfortable with a brute-force approach and is trying to head a particular direction and just keeps finding that unsatisfactory. I also recognize that my cell T12 formula may be too much for it to handle. It just won't let me have multiple targets so I was trying to come up with a way for it to guarantee no false positives (e.g., if you just add all the difference cells in N10-S10 and U2-U6, which should all be zero, you can actually get solutions where some of the columns are non-zero but add up to zero because of positives and negatives...and those are result cells, so I can't similarly constrain them, I think).
Anyhow, here's the number set:
2 9 3 2 3
9 9 8 4 1
2 6 5 2 6
3 1 6 8 7
6 8 3 6 9
Row totals = 13, 4, 7, 19, 32 from top to bottom
Column totals = 13, 18, 8, 20, 16
I'd give you the answer...but where's the fun in that?

Resources