On the edges of the hypercube

Python 2, 54 56 62 bytes

lambda n:{tuple({k/n,k/n^1<<k%n})for k in range(n<<n)}

Duplicate edges are removed by making a set of sets, except Python requires that set elements are hashable, so they are converted to a tuples. Note that the sets {a,b} and {b,a} are equal and convert to the same tuple. xsot saved 2 bytes with n<<n.

This can be cut down to 49 bytes if strings of sets are an OK output format

lambda n:{`{k/n,k/n^1<<k%n}`for k in range(n<<n)}

which gives output like

set(['set([1, 3])', 'set([2, 3])', 'set([0, 2])', 'set([0, 1])'])

lambda n:[(k/n,k/n^1<<k%n)for k in range(n*2**n)if k/n&1<<k%n]

First, let's look at an older version of the solution.

lambda n:[(i,i^2**j)for i in range(2**n)for j in range(n)if i&2**j]

Each a number in the interval [0,2^n) corresponds to a vertex with coordinates given by its n-bit binary strings. To vertices are adjacent if they differ in a single bit, i.e. if one is obtained from the other by xor-ing a power of 2.

This anonymous function generates all possible edges by taking every vertex and every bit position to flip. To avoid duplicating an edge in both directions, only 1's are flipped to 0's.

In the more golfed solution, k is used to encode both i and j via k=n*i+j, from which (i,j) can be extracted as (k/n,k%n). This saves a loop in the comprehension. The powers of 2 are done as 1<< to have the right operator precedence.

An alternative approach of generating each pair of vertices and checking if they are a bit flip apart seems longer (70 bytes):

lambda n:[(i,x)for i in range(2**n)for x in range(i)if(i^x)&(i^x)-1<1] 

Mathematica, 48 24 bytes

EdgeList@*HypercubeGraph

Just an anonymous function that uses built-ins.


Jelly, 13 bytes

ạ/S’
2ṗœc2ÇÐḟ

Try it here. For input 3, the output is:

[[[1, 1, 1], [1, 1, 2]],
 [[1, 1, 1], [1, 2, 1]],
 [[1, 1, 1], [2, 1, 1]],
 [[1, 1, 2], [1, 2, 2]],
 [[1, 1, 2], [2, 1, 2]],
 [[1, 2, 1], [1, 2, 2]],
 [[1, 2, 1], [2, 2, 1]],
 [[1, 2, 2], [2, 2, 2]],
 [[2, 1, 1], [2, 1, 2]],
 [[2, 1, 1], [2, 2, 1]],
 [[2, 1, 2], [2, 2, 2]],
 [[2, 2, 1], [2, 2, 2]]]

I hope [1, 1, 1] etc. is an okay “name”.

Explanation

The first line is a “predicate” on a pair of edges: [A, B] ạ/S’ is equal to sum(abs(A - B)) - 1, which is zero (false-y) iff A and B differ in exactly one coordinate.

The second line is the main program:

  • Generate all edges with 2ṗ (Cartesian power of [1, 2]).
  • Get all possible pairs using œc2 (combinations of size two without replacement).
  • Keep only elements satisfying the predicate defined earlier (ÐḟÇ).