Calculating eigenvector centrality using NetworkX - networkx

I'm using the NetworkX library to work with some small- to medium-sized unweighted, unsigned, directed graphs representing usage of a Web 2.0 site (smallest graph: less than two dozen nodes, largest: a few thousand). One of the things I want to calculate is eigenvector centrality, as follows:
>>> eig = networkx.eigenvector_centrality(my_graph)
>>> eigs = [(v,k) for k,v in eig.iteritems()]
>>> eigs.sort()
>>> eigs.reverse()
However, this gives unexpected results: nodes with 0 outdegree but receiving inward arcs from very central nodes appear at the very back of the list with 0.0 eigenvector centrality (not being a mathematician I may have got this confused, but I don't think that outward arcs should make any difference to a node's centrality to a directed graph). In the course of investigating these results, I noticed from the documentation that NetworkX calculates 'right' eigenvector centrality by default; out of curiosity, I decided to calculate 'left' eigenvector centrality by the recommended method, i.e. reversing the graph before calculating eigenvector centrality (see Networkx documentation). To my surprise, I got exactly the same result: every node was calculated to have exactly the same eigenvector centrality as before. I think this should be a very unlikely outcome (see Wikipedia article), but I have since replicated it with all the graphs I'm working with. Can anyone explain to me what I'm doing wrong?
N.B. Using the NetworkX implementation of the PageRank algorithm provides the results I was expecting, i.e. nodes receiving inward arcs from very central nodes have high centrality even if their outdegree is 0. PageRank is usually considered to be a variant of eigenvector centrality (see Wikipedia article).
Edit: following a request from Aric, I have included some data. This is an anonymised version of my smallest graph. (I couldn't post toy data in case the problem is specific to the structure of my graphs.) Running the code below on my machine (with Python 2.7) appears to reveal (a) that each node's right and left eigenvector centrality are the same, and (b) that nodes with outdegree 0 invariably also have eigenvector centrality 0, even if they are quite central to the graph as a whole (e.g. node 61).
import networkx
anon_e_list = [(10, 59), (10, 15), (10, 61), (15, 32), (16, 31), (16, 0), (16, 37), (16, 54), (16, 45), (16, 56), (16, 10), (16, 8), (16, 36), (16, 24), (16, 30), (18, 34), (18, 36), (18, 30), (19, 1), (19, 3), (19, 51), (19, 21), (19, 40), (19, 41), (19, 30), (19, 14), (19, 61), (21, 64), (26, 1), (31, 1), (31, 3), (31, 51), (31, 62), (31, 33), (31, 40), (31, 23), (31, 30), (31, 18), (31, 13), (31, 46), (31, 61), (32, 3), (32, 2), (32, 33), (32, 6), (32, 7), (32, 9), (32, 15), (32, 17), (32, 18), (32, 23), (32, 30), (32, 5), (32, 27), (32, 34), (32, 35), (32, 38), (32, 40), (32, 42), (32, 43), (32, 46), (32, 47), (32, 62), (32, 56), (32, 57), (32, 59), (32, 64), (32, 61), (33, 0), (33, 31), (33, 2), (33, 7), (33, 9), (33, 10), (33, 12), (33, 64), (33, 14), (33, 46), (33, 16), (33, 17), (33, 18), (33, 19), (33, 20), (33, 21), (33, 22), (33, 23), (33, 30), (33, 26), (33, 28), (33, 11), (33, 34), (33, 32), (33, 35), (33, 37), (33, 38), (33, 39), (33, 41), (33, 43), (33, 45), (33, 24), (33, 47), (33, 48), (33, 49), (33, 58), (33, 62), (33, 53), (33, 54), (33, 55), (33, 60), (33, 57), (33, 59), (33, 5), (33, 52), (33, 63), (33, 61), (34, 58), (34, 4), (34, 33), (34, 20), (34, 55), (34, 28), (34, 11), (34, 64), (35, 18), (35, 60), (35, 61), (37, 34), (37, 48), (37, 49), (37, 18), (37, 33), (37, 39), (37, 21), (37, 42), (37, 26), (37, 59), (37, 44), (37, 12), (37, 11), (37, 61), (41, 3), (41, 50), (41, 18), (41, 52), (41, 33), (41, 54), (41, 19), (41, 22), (41, 5), (41, 46), (41, 25), (41, 44), (41, 13), (41, 62), (41, 29), (44, 32), (44, 3), (44, 18), (44, 33), (44, 40), (44, 41), (44, 30), (44, 23), (44, 61), (50, 17), (50, 37), (50, 62), (50, 41), (50, 25), (50, 43), (50, 27), (50, 28), (50, 29), (54, 33), (54, 41), (54, 10), (54, 59), (54, 63), (54, 61), (58, 62), (58, 46), (59, 31), (59, 34), (59, 30), (59, 49), (59, 18), (59, 33), (59, 9), (59, 10), (59, 8), (59, 13), (59, 24), (59, 61), (60, 34), (60, 16), (60, 35), (60, 50), (60, 4), (60, 6), (60, 59), (60, 24), (63, 40), (63, 33), (63, 30), (63, 61), (63, 53)]
my_graph = networkx.DiGraph()
my_graph.add_edges_from(anon_e_list)
r_eig = networkx.eigenvector_centrality(my_graph)
my_graph2 = my_graph.reverse()
l_eig = networkx.eigenvector_centrality(my_graph2)
for nd in my_graph.nodes():
print 'node: {} indegree: {} outdegree: {} right eig: {} left eig: {}'.format(nd,my_graph.in_degree(nd),my_graph.out_degree(nd),r_eig[nd],l_eig[nd])

These two lines
my_graph2 = my_graph.copy()
my_graph2.reverse()
should be replaced with
my_graph2 = my_graph.reverse()
since the reverse() method by default returns a copy of the graph.

Related

Finetuning LayoutLM on FUNSD-like dataset - index out of range in self

I'm experimenting with huggingface transformers to finetune microsoft/layoutlmv2-base-uncased through AutoModelForTokenClassification on my custom dataset that is similar to FUNSD (pre-processed and normalized). After a few iterations of training I get this error :
Traceback (most recent call last):
File "layoutlmV2/train.py", line 137, in <module>
trainer.train()
File "..../lib/python3.8/site-packages/transformers/trainer.py", line 1409, in train
return inner_training_loop(
File "..../lib/python3.8/site-packages/transformers/trainer.py", line 1651, in _inner_training_loop
tr_loss_step = self.training_step(model, inputs)
File "..../lib/python3.8/site-packages/transformers/trainer.py", line 2345, in training_step
loss = self.compute_loss(model, inputs)
File "..../lib/python3.8/site-packages/transformers/trainer.py", line 2377, in compute_loss
outputs = model(**inputs)
File "..../lib/python3.8/site-packages/torch/nn/modules/module.py", line 1131, in _call_impl
return forward_call(*input, **kwargs)
File "..../lib/python3.8/site-packages/transformers/models/layoutlmv2/modeling_layoutlmv2.py", line 1228, in forward
outputs = self.layoutlmv2(
File "..../lib/python3.8/site-packages/torch/nn/modules/module.py", line 1131, in _call_impl
return forward_call(*input, **kwargs)
File "..../lib/python3.8/site-packages/transformers/models/layoutlmv2/modeling_layoutlmv2.py", line 902, in forward
text_layout_emb = self._calc_text_embeddings(
File "..../lib/python3.8/site-packages/transformers/models/layoutlmv2/modeling_layoutlmv2.py", line 753, in _calc_text_embeddings
spatial_position_embeddings = self.embeddings._calc_spatial_position_embeddings(bbox)
File "..../lib/python3.8/site-packages/transformers/models/layoutlmv2/modeling_layoutlmv2.py", line 93, in _calc_spatial_position_embeddings
h_position_embeddings = self.h_position_embeddings(bbox[:, :, 3] - bbox[:, :, 1])
File "..../lib/python3.8/site-packages/torch/nn/modules/module.py", line 1131, in _call_impl
return forward_call(*input, **kwargs)
File "..../lib/python3.8/site-packages/torch/nn/modules/sparse.py", line 158, in forward
return F.embedding(
File "..../lib/python3.8/site-packages/torch/nn/functional.py", line 2203, in embedding
return torch.embedding(weight, input, padding_idx, scale_grad_by_freq, sparse)
IndexError: index out of range in self
After further inspection (vocab size, bboxes, dimensions, classes...) I noticed that there's negative values inside the input tensor causing the error. While input tensors of successful previous iterations have unsigned integers only. These negative numbers are returned by _calc_spatial_position_embeddings(self, bbox) in modeling_layoutlmv2.py
line 92 :
h_position_embeddings = self.h_position_embeddings(bbox[:, :, 3] - bbox[:, :, 1])
What may cause the returned input values to be negative?
What could I do to prevent this error from happening?
Example of the input tensor that triggers the error in torch.embedding(weight, input, padding_idx, scale_grad_by_freq, sparse) :
tensor([[ 0, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12,
12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 5, 5, 5, 5, 5, 5, -6, -6, -6, -6, -6, -6, 1, 1, 1, 1, 1,
5, 5, 5, 5, 5, 5, 7, 5, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0]])
After double checking the dataset and specifically the coordinates of the labels, I've found that some rows bbox coordinates lead to zero width or height. Here's a simplified example:
x1, y1, x2, y2 = dataset_row["bbox"]
print((x2-x1 < 1) or (y2-y1 < 1)) #output is sometimes True
After removing these labels from the dataset, the issue was resolved.

Can rrule start at half past hour?

Is it possible to create a rrule that runs every 30 minutes but starts and ends at the middle of an hour? If rrule would accept non-integer parameters like byhour=range(16.5,19) that would be great, but unfortunately only integer is accepted.
In my case the times would be 16:30, 17:00, 17:30, 18:00 and 18:30 every weekday. All I can do is from 16:00 to 18:30 as follows:
from dateutil.rrule import *
from dateutil.parser import parse
list(rrule(MINUTELY, interval=30, count=20, byhour=range(16,19), byminute=(0,30), byweekday=(MO,TU,WE,TH,FR), dtstart=parse("20220602T070000")))
...with the following result:
[datetime.datetime(2022, 6, 2, 16, 0),
datetime.datetime(2022, 6, 2, 16, 30),
datetime.datetime(2022, 6, 2, 17, 0),
datetime.datetime(2022, 6, 2, 17, 30),
datetime.datetime(2022, 6, 2, 18, 0),
datetime.datetime(2022, 6, 2, 18, 30),
datetime.datetime(2022, 6, 3, 16, 0),
datetime.datetime(2022, 6, 3, 16, 30),
datetime.datetime(2022, 6, 3, 17, 0),
datetime.datetime(2022, 6, 3, 17, 30),
datetime.datetime(2022, 6, 3, 18, 0),
datetime.datetime(2022, 6, 3, 18, 30),
datetime.datetime(2022, 6, 6, 16, 0),
datetime.datetime(2022, 6, 6, 16, 30),
datetime.datetime(2022, 6, 6, 17, 0),
datetime.datetime(2022, 6, 6, 17, 30),
datetime.datetime(2022, 6, 6, 18, 0),
datetime.datetime(2022, 6, 6, 18, 30),
datetime.datetime(2022, 6, 7, 16, 0),
datetime.datetime(2022, 6, 7, 16, 30)]
I was hoping rrule has more flexibility than crontab...
I found a solution using rrset.exrule:
from dateutil.rrule import *
from dateutil.parser import parse
myrrule = rrule(MINUTELY, interval=30, count=20, byhour=range(16,19), byminute=(0,30), byweekday=(MO,TU,WE,TH,FR), dtstart=parse("20220602T070000"))
myexrule = rrule(DAILY, interval=1, count=4, byhour=16, byminute=0, byweekday=(MO,TU,WE,TH,FR), dtstart=parse("20220602T070000"))
rrset = rruleset()
rrset.rrule(myrrule)
rrset.exrule(myexrule)
list(rrset)
with the following result:
[datetime.datetime(2022, 6, 2, 16, 30),
datetime.datetime(2022, 6, 2, 17, 0),
datetime.datetime(2022, 6, 2, 17, 30),
datetime.datetime(2022, 6, 2, 18, 0),
datetime.datetime(2022, 6, 2, 18, 30),
datetime.datetime(2022, 6, 3, 16, 30),
datetime.datetime(2022, 6, 3, 17, 0),
datetime.datetime(2022, 6, 3, 17, 30),
datetime.datetime(2022, 6, 3, 18, 0),
datetime.datetime(2022, 6, 3, 18, 30),
datetime.datetime(2022, 6, 6, 16, 30),
datetime.datetime(2022, 6, 6, 17, 0),
datetime.datetime(2022, 6, 6, 17, 30),
datetime.datetime(2022, 6, 6, 18, 0),
datetime.datetime(2022, 6, 6, 18, 30),
datetime.datetime(2022, 6, 7, 16, 30)]

Filter Scala Matrix with condition

I have the given matrix in Scala:
val matrix = Array([30, 0, 13, 21, 25, 15],
[55, 47, 26, 54, 44, 3],
[21, 19, 23, 47, 29, 13],
[52, 50, 44, 14, 21, 24],
[10, 37, 0, 22, 17, 58],
[36, 55, 48, 27, 13, 35])
I need to filter the matrix (values from 2nd column > 40 and values fom 4rd column <45)
Can i do this somehow with the matrix.filter method?
You can try this way:
scala> :paste
// Entering paste mode (ctrl-D to finish)
val matrix = Array(Array(30, 0, 13, 21, 25, 15),
Array(55, 47, 26, 54, 44, 3),
Array(21, 19, 23, 47, 29, 13),
Array(52, 50, 44, 14, 21, 24),
Array(10, 37, 0, 22, 17, 58),
Array(36, 55, 48, 27, 13, 35))
// Exiting paste mode, now interpreting.
matrix: Array[Array[Int]] = Array(Array(30, 0, 13, 21, 25, 15), Array(55, 47, 26, 54, 44, 3), Array(21, 19, 23, 47, 29, 13), Array(52, 50, 44, 14, 21, 24), Array(10, 37, 0, 22, 17, 58), Array(36, 55, 48, 27, 13, 35))
scala> matrix.filter(x => x(1) > 40 && x(3) < 45)
res0: Array[Array[Int]] = Array(Array(52, 50, 44, 14, 21, 24), Array(36, 55, 48, 27, 13, 35))

Different CRC32 values in Java and swift

I'm in the process of writing a utility in Swift which can be used to calculate CRC32 checksum of an input data . A similar utility exists in Java which we are using extensively and has been working well for us.
The Java Utility uses java.util.zip.CRC32 to calculate the checksum. Pseudo code is as follows :
Java code:
private void transferFileData(short index, byte[] data, long dataSize) {
CRC32 crc32 = new CRC32();
long crc = crc32.update(data, (int) dataSize);
System.out.println("CRC32 : " + crc);
}
The Swift uses the CRC32 (import CryptoSwift) CryptoSwift code for generating the checksum in swift is as follows :
Swift code:
func crc32Func(_ item:[Int8] ) {
let data = Data(bytes: item, count: item.count)
let byte = data.bytes
let crc32 = byte.crc32()
print("checksum == \(crc32)"
}
The output from the Java code is :
Checksum in Java : 3771181957
The output from the swift code is :
Checksum in swift : 1894162356
Why the checksum values are not the same?
This is the code applied by Swift as below:
The data type is [Int8]
The data size is 450 bytes.
let item:
[Int8] = [45, 35, 76, 70, 67, 68, 95, 70, 79, 84, 65, 95, 70, 87, 95,
70, 85, 76, 76, 10, 80, 75, 71, 95, 86 , 69, 82, 83, 73, 79, 78, 58,
51, 46, 48, 46, 48, 10, 66, 65, 83, 69, 95, 86, 69, 82, 83, 73, 79, 78
, 58, 10, 72, 65, 83, 72, 58, 51, 97, 57, 98, 51, 99, 52, 56, 57, 52,
56, 56, 53, 49, 50, 53, 52, 55 , 48, 51, 49, 54, 48, 57, 56, 48, 101,
98, 101, 51, 54, 54, 10, 80, 75, 71, 95, 83, 73, 90, 69, 58, 49 , 51,
49, 48, 55, 50, 48, 10, 26, 0, 0, 5, 32, -79, 11, 5, 8, -39, -5, 4, 8,
-35, -5, 4, 8, -15, -5, 4, 8, -13, -5, 4, 8, -11, -5, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -31, -15, 10, 8, -9, -5, 4, 8,
0, 0, 0, 0, -127, -14, 10, 8, -27, -14, 10, 8, 1, 12, 5, 8, 1, 12, 5,
8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1,
12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12,
5, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8,
-7, -5, 4, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8, 9, -4,
4, 8, 25, -4, 4, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12, 5,
8, 1, 12, 5, 8, 57, -4, 4, 8, 1, 12, 5, 8, 73, -4, 4, 8, 89, -4, 4, 8,
105, -4, 4, 8, 1, 12, 5, 8, -39, -4, 4, 8, 1, 12, 5, 8, 1, 12, 5, 8,
1, 12, 5, 8, 41, -4, 4, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1,
12, 5 , 8, 1, 12, 5, 8, 1, 12, 5, 8, 121, -4, 4, 8, -119, -4, 4, 8, 1,
12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12,
5, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8,
1, 12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8, 1, 12, 5, 8, -103, -4]
is input.
Java input:
byte[] data
The type is long and the data entered is the same as [Int8] of swift data.
The CRC you are getting from your Swift code (whatever that actual code is) is correct. The CRC you are getting from your Java code (whatever that actual code is) is not correct.
There is no way to know what you're doing wrong in your Java code without at least being able to see that code.

Finding a value in a list, which equals to the sum of the previous value and another value from different list

The title might seem a bit confusing, but what I'm trying to do is rather simple.
I have 2 lists, one is:
List(12, 14, 16, 24, 26, 32, 36, 43, 44, 46, 52, 54, 56, 62, 66, 72, 74, 76)
And the second one is:
List(11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 32)
I want to iterate through the first list and see if there exists a value in the first list that would be the sum of a previous value and another value from the second list. If a value like that exists, it should get summed with the same value from the second list and check if a value like that exists in the first list and so on until it reaches the maximum obtainable value in the first list.
For example: If we take the value 16 from the first list, and keep summing it with 28, we get the values:
16, 44 and 72
Or: We take 24 from the first list, keep adding 19 to it and getting the values:
24, 43 and 62
If, including the starting value, at least 2 more values can't be found by adding the same number, it should just take the next value in the list and do the same calculations.
Any help would be appreciated, I tried using the fold and reduce functions, but I couldn't get them to work.
EDIT:
Tried using Stream.iterate to do the job, but It didn't really work
val iTried = Stream.iterate(0)(i => i + 1)
.takeWhile(i => coordinatesRows(i)
.toString exists coordinatesRows + valuesForDiag(i))
Also tried making a function of my own:
def sortDiagonally(xs: List[Int]) ={
/**
**/
val start = xs.head
Stream.from(1).flatMap{ value =>
xs exists (start + valuesForDiag == xs)
}
I'm still learning the language, so I'm not too familiar with all the inns and outs of Scala.
EDIT 2:
By using these 2 lists, I would like to get the output of:
List(List(16, 44, 72), List(24, 43, 62), List(32, 54, 76), List(36, 54, 72), List(12, 24, 36), List(12, 44, 76))
I also removed the value of 10, 20 and 30 from the 2nd list, as it shouldn't have been there.
val vals = List(12, 14, 16, 24, 26, 32, 36, 43, 44, 46, 52, 54, 56, 62, 66, 72, 74, 76)
val mods = List(10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32)
def find(l: List[Int]): Set[Int] = l match {
case Nil => Set.empty[Int]
case x :: xs =>
xs.filter{
i => mods.exists(j => (i - x) % j == 0)
}.toSet ++ find(xs)
}
find(vals)
Returns:
Set(56, 24, 52, 46, 74, 32, 44, 54, 76, 66, 72, 43, 26, 36, 62)
All matching values:
def find(l: List[Int]): List[(Int, Int, Int)] = l match {
case Nil => Nil
case x :: xs =>
xs.flatMap{
i => mods.collect{ case j if (i - x) % j == 0 => (x, i, j) }
} ++ find(xs)
}
println(find(vals))
Returns:
List((12,24,12), (12,26,14), (12,32,10), (12,32,20), (12,36,12), (12,36,24), (12,43,31), (12,44,16), (12,44,32), (12,46,17), (12,52,10), (12,52,20), (12,54,14), (12,54,21), (12,56,11), (12,56,22), (12,62,10), (12,62,25), (12,66,18), (12,66,27), (12,72,10), (12,72,12), (12,72,15), (12,72,20), (12,72,30), (12,74,31), (12,76,16), (12,76,32), (14,24,10), (14,26,12), (14,32,18), (14,36,11), (14,36,22), (14,43,29), (14,44,10), (14,44,15), (14,44,30), (14,46,16), (14,46,32), (14,52,19), (14,54,10), (14,54,20), (14,56,14), (14,56,21), (14,62,12), (14,62,16), (14,62,24), (14,66,13), (14,66,26), (14,72,29), (14,74,10), (14,74,12), (14,74,15), (14,74,20), (14,74,30), (14,76,31), (16,26,10), (16,32,16), (16,36,10), (16,36,20), (16,43,27), (16,44,14), (16,44,28), (16,46,10), (16,46,15), (16,46,30), (16,52,12), (16,52,18), (16,54,19), (16,56,10), (16,56,20), (16,62,23), (16,66,10), (16,66,25), (16,72,14), (16,72,28), (16,74,29), (16,76,10), (16,76,12), (16,76,15), (16,76,20), (16,76,30), (24,36,12), (24,43,19), (24,44,10), (24,44,20), (24,46,11), (24,46,22), (24,52,14), (24,52,28), (24,54,10), (24,54,15), (24,54,30), (24,56,16), (24,56,32), (24,62,19), (24,66,14), (24,66,21), (24,72,12), (24,72,16), (24,72,24), (24,74,10), (24,74,25), (24,76,13), (24,76,26), (26,36,10), (26,43,17), (26,44,18), (26,46,10), (26,46,20), (26,52,13), (26,52,26), (26,54,14), (26,54,28), (26,56,10), (26,56,15), (26,56,30), (26,62,12), (26,62,18), (26,66,10), (26,66,20), (26,72,23), (26,74,12), (26,74,16), (26,74,24), (26,76,10), (26,76,25), (32,43,11), (32,44,12), (32,46,14), (32,52,10), (32,52,20), (32,54,11), (32,54,22), (32,56,12), (32,56,24), (32,62,10), (32,62,15), (32,62,30), (32,66,17), (32,72,10), (32,72,20), (32,74,14), (32,74,21), (32,76,11), (32,76,22), (36,46,10), (36,52,16), (36,54,18), (36,56,10), (36,56,20), (36,62,13), (36,62,26), (36,66,10), (36,66,15), (36,66,30), (36,72,12), (36,72,18), (36,74,19), (36,76,10), (36,76,20), (43,54,11), (43,56,13), (43,62,19), (43,66,23), (43,72,29), (43,74,31), (43,76,11), (44,54,10), (44,56,12), (44,62,18), (44,66,11), (44,66,22), (44,72,14), (44,72,28), (44,74,10), (44,74,15), (44,74,30), (44,76,16), (44,76,32), (46,56,10), (46,62,16), (46,66,10), (46,66,20), (46,72,13), (46,72,26), (46,74,14), (46,74,28), (46,76,10), (46,76,15), (46,76,30), (52,62,10), (52,66,14), (52,72,10), (52,72,20), (52,74,11), (52,74,22), (52,76,12), (52,76,24), (54,66,12), (54,72,18), (54,74,10), (54,74,20), (54,76,11), (54,76,22), (56,66,10), (56,72,16), (56,74,18), (56,76,10), (56,76,20), (62,72,10), (62,74,12), (62,76,14), (66,76,10))
Finally
def find(l: List[Int]): List[List[Int]] = l match {
case Nil => Nil
case x :: xs =>
mods.map {
mod => x :: xs.collect { case c if (c - x) % mod == 0 => c }
}.filter(_.size > 1) ++ find(xs)
}
find(vals)
Returns:
List(List(12, 32, 52, 62, 72), List(12, 56), List(12, 24, 36, 72), List(12, 26, 54), List(12, 72), List(12, 44, 76), List(12, 46), List(12, 66), List(12, 32, 52, 72), List(12, 54), List(12, 56), List(12, 36), List(12, 62), List(12, 66), List(12, 72), List(12, 43, 74), List(12, 44, 76), List(14, 24, 44, 54, 74), List(14, 36), List(14, 26, 62, 74), List(14, 66), List(14, 56), List(14, 44, 74), List(14, 46, 62), List(14, 32), List(14, 52), List(14, 54, 74), List(14, 56), List(14, 36), List(14, 62), List(14, 66), List(14, 43, 72), List(14, 44, 74), List(14, 76), List(14, 46), List(16, 26, 36, 46, 56, 66, 76), List(16, 52, 76), List(16, 44, 72), List(16, 46, 76), List(16, 32), List(16, 52), List(16, 54), List(16, 36, 56, 76), List(16, 62), List(16, 66), List(16, 43), List(16, 44, 72), List(16, 74), List(16, 46, 76), List(24, 44, 54, 74), List(24, 46), List(24, 36, 72), List(24, 76), List(24, 52, 66), List(24, 54), List(24, 56, 72), List(24, 43, 62), List(24, 44), List(24, 66), List(24, 46), List(24, 72), List(24, 74), List(24, 76), List(24, 52), List(24, 54), List(24, 56), List(26, 36, 46, 56, 66, 76), List(26, 62, 74), List(26, 52), List(26, 54), List(26, 56), List(26, 74), List(26, 43), List(26, 44, 62), List(26, 46, 66), List(26, 72), List(26, 74), List(26, 76), List(26, 52), List(26, 54), List(26, 56), List(32, 52, 62, 72), List(32, 43, 54, 76), List(32, 44, 56), List(32, 46, 74), List(32, 62), List(32, 66), List(32, 52, 72), List(32, 74), List(32, 54, 76), List(32, 56), List(32, 62), List(36, 46, 56, 66, 76), List(36, 72), List(36, 62), List(36, 66), List(36, 52), List(36, 54, 72), List(36, 74), List(36, 56, 76), List(36, 62), List(36, 66), List(43, 54, 76), List(43, 56), List(43, 62), List(43, 66), List(43, 72), List(43, 74), List(44, 54, 74), List(44, 66), List(44, 56), List(44, 72), List(44, 74), List(44, 76), List(44, 62), List(44, 66), List(44, 72), List(44, 74), List(44, 76), List(46, 56, 66, 76), List(46, 72), List(46, 74), List(46, 76), List(46, 62), List(46, 66), List(46, 72), List(46, 74), List(46, 76), List(52, 62, 72), List(52, 74), List(52, 76), List(52, 66), List(52, 72), List(52, 74), List(52, 76), List(54, 74), List(54, 76), List(54, 66), List(54, 72), List(54, 74), List(54, 76), List(56, 66, 76), List(56, 72), List(56, 74), List(56, 76), List(62, 72), List(62, 74), List(62, 76), List(66, 76))