3
$\begingroup$

Background Info

I am interested in a better way of doing the following:

I want to find the weights of the following codewords (the weight of a codeword here can be defined as the number of nonzero entries in that codeword e.g the weight of the codeword (1,0,1,1) would be 3):

{{0,0,0,0},{0,0,0,1},{0,0,1,0},{0,0,1,1}} 

The weights of these codewords would be 0,1,1 and 2 respectively.

Let $A_{i}$ denote the number of codewords with weight $i$.

So for this example, there is one codeword of weight $0$ so $A_{0}=1$

There are two codewords of weight $1$, so $A_{1}=2$

There is one codeword of weight $2$, so $A_{2}=1$

My attempt

Define the codewords and their respective weights

In[1]= codewords = {{0, 0, 0, 0}, {1, 0, 0, 0}, {0, 1, 0, 0}, {1, 1, 0, 0}} In[2]= weights = Total[codewords[[#]]] & /@ Range[Length[codewords]] Out[1]= {{0, 0, 0, 0}, {1, 0, 0, 0}, {0, 1, 0, 0}, {1, 1, 0, 0}} Out[2]= {0, 1, 1, 2} 

Now define $A_{i}$ as being the number of codewords of weight $i$

In[3]= A0 = Length[If[weights[[#]] == 0, 0, Nothing] & /@ Range[Length[weights]]] In[4]= A1 = Length[If[weights[[#]] == 1, 1, Nothing] & /@ Range[Length[weights]]] In[5]= A2 = Length[If[weights[[#]] == 2, 2, Nothing] & /@ Range[Length[weights]]] Out[3]= 1 Out[4]= 2 Out[5]= 1 

The above code works, but there must be a more elegant solution, perhaps one that doesn't need so much manual interference. If anyone has a better idea, please let me know!

$\endgroup$
1
  • 2
    $\begingroup$ Just a pedagogical note... One nice thing about Map is that you don't need to keep track of indices yourself. So, in your solution, you can replace weights = Total[codewords[[#]]] & /@ Range[Length[codewords]] with weights = Total /@ codewords $\endgroup$ Commented Nov 7, 2023 at 18:43

4 Answers 4

2
$\begingroup$

Using GroupBy:

codewords = {{0, 0, 0, 0}, {0, 0, 0, 1}, {0, 0, 1, 0}, {0, 0, 1, 1}}; GroupBy[codewords, Total, Length] 

<|0 -> 1, 1 -> 2, 2 -> 1|>

$\endgroup$
4
$\begingroup$

I cannot comment on the nice pieces of Mathematica code suggested by the other answerers, but as a (former) coding theorist I want to remark that people working in this area often use a generating function (a weight enumerator polynomial) for storing and manipulating this kind of information.

If we denote the Hamming weight of a word $r$ by $w(r)$, the weight enumerating polynomial $W_C(x)$ of a code $C$ of length $n$ is simply $$ W_C(x):=\sum_{r\in C}x^{w(r)}=\sum_{i=0}^nA_ix^i, $$ where, for all $i$ in the range $0\le i\le n$, $A_i$ is the number of words of weight $i$.

With my very vanilla skills in Mathematica-coding it could go as follows (assuming binary codes only):

Weight[r_] := Sum[r[[i]], {i, 1, Length[r]}] WeightEnumerator[C_] := Sum[x^Weight[C[[i]]], {i, 1, Length[C]}] 

So for example

codewords = {{0, 0, 0, 0}, {0, 1, 0, 1}, {1, 0, 1, 0}, {1, 1, 1, 1}} WeightEnumerator[codewords] 

gives the output

1 + 2 x^2 + x^4 

meaning that there was one word of weight zero, two of weight two and one of weight four.

$\endgroup$
4
  • 3
    $\begingroup$ GroupBy[codewords, Total, Length] // KeyValueMap[#2 x^#1 &, #] & // Total $\endgroup$ Commented Nov 8, 2023 at 14:09
  • 1
    $\begingroup$ This is fantastic. I had wanted to move on to checking that Ai and Bi satisfy the MacWilliams identity, so this is a great jumping off point for that! $\endgroup$ Commented Nov 8, 2023 at 15:47
  • 1
    $\begingroup$ @QC123_367 Please compare this (performancewise) with the snippet Syed suggested. They know more about Mathematica-programming than I ever will, so for larger codes theirs is likely the faster method. For MacWilliams identity you may prefer to use the two variable version. If we denote by $f(x)$ the polynomial my snippet produces, the two variable version is $W_C(x,y)=f(x/y)*y^n$. MacWilliams is usually written using that polynomial. $\endgroup$ Commented Nov 8, 2023 at 20:54
  • 1
    $\begingroup$ @JyrkiLahtonen have indeed used Syed's code. And yes, thank you, I have used the two variable version for MacWilliams identity. I adapted Syed's code so that the two variable weight enumerator polynomial looked something like: Module[{n, weightenumerator}, n = Length[codewords[[1]]]; weightenumerator = GroupBy[codewords2, Total, Length] // KeyValueMap[#2 x^(n - #1) y^#1 &, #] & // Total; weightenumerator] Which outputs $x^{4} + 2x^{3}y + x^{2}y^{2}$ $\endgroup$ Commented Nov 10, 2023 at 10:40
2
$\begingroup$
codewords = {{0, 0, 0, 0}, {1, 0, 0, 0}, {0, 1, 0, 0}, {1, 1, 0, 0}} a = Count[1] /@ codewords 

{0, 1, 1, 2}

b = Counts @ a 

<|0 -> 1, 1 -> 2, 2 -> 1|>

Values[b] 

{1, 2, 1}

Assignment to variables as per your question:

{A0, A1, A2} = Values[b]; 

Better in my opinion

A = Values[b]; 

with Part syntax:

A[[2]] 

2

$\endgroup$
1
$\begingroup$

Given

codewords = {{0, 0, 0, 0}, {0, 0, 0, 1}, {0, 0, 1, 0}, {0, 0, 1, 1}} 

and assuming that all letters are either 0 or 1, you could do this:

weightCounts = CountsBy[codewords, Total] (* <|0 -> 1, 1 -> 2, 2 -> 1|> *) 

Now weightCounts corresponds to your A and would work almost exactly like you want:

weightCounts[0] (* 1 *) weightCounts[1] (* 2 *) weightCounts[2] (* 1 *) 

If there are more than just the two letters 0,1, and if only nonzero letters count for weight, then you could replace the above assignment to weightCounts with any of these that fit your scenario:

weightCounts = CountsBy[codewords, Length@*DeleteCases[0]] weightCounts = CountsBy[codewords, Count[_?Positive]] weightCounts = CountsBy[codewords, Count[_?(# != 0 &)]] 
$\endgroup$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.