Save and load solutions

Let us use the maximum independent set problem on Petersen graph as an example. The following code enumerates all independent sets.

using GenericTensorNetworks, Graphs

problem = GenericTensorNetwork(IndependentSet(Graphs.smallgraph(:petersen)))

all_independent_sets = solve(problem, ConfigsAll())[]
{0000000000, 1000000000, 0000010000, 0000000001, 1000000001, 0000010001, 0000001000, 1000001000, 0000011000, 0000100000, 0000110000, 0000101000, 0000111000, 0000000010, 1000000010, 0000000011, 1000000011, 0000100010, 0010000000, 1010000000, 0010010000, 0010000001, 1010000001, 0010010001, 0010001000, 1010001000, 0010011000, 0010100000, 0010110000, 0010101000, 0010111000, 0010000010, 1010000010, 0010000011, 1010000011, 0010100010, 0100000000, 0100010000, 0100000001, 0100010001, 0100100000, 0100110000, 0100000010, 0100000011, 0100100010, 0000000100, 1000000100, 0000001100, 1000001100, 0000100100, 0000101100, 0000000110, 1000000110, 0000100110, 0100000100, 0100100100, 0100000110, 0100100110, 0001000000, 1001000000, 0001010000, 0001000001, 1001000001, 0001010001, 0001001000, 1001001000, 0001011000, 0101000000, 0101010000, 0101000001, 0101010001, 0001000100, 1001000100, 0001001100, 1001001100, 0101000100}

The return value has type ConfigEnumerator. We can use save_configs and load_configs to save and read a ConfigEnumerator instance to the disk.

filename = tempname()

save_configs(filename, all_independent_sets; format=:binary)

loaded_sets = load_configs(filename; format=:binary, bitlength=10)
{0000000000, 1000000000, 0000010000, 0000000001, 1000000001, 0000010001, 0000001000, 1000001000, 0000011000, 0000100000, 0000110000, 0000101000, 0000111000, 0000000010, 1000000010, 0000000011, 1000000011, 0000100010, 0010000000, 1010000000, 0010010000, 0010000001, 1010000001, 0010010001, 0010001000, 1010001000, 0010011000, 0010100000, 0010110000, 0010101000, 0010111000, 0010000010, 1010000010, 0010000011, 1010000011, 0010100010, 0100000000, 0100010000, 0100000001, 0100010001, 0100100000, 0100110000, 0100000010, 0100000011, 0100100010, 0000000100, 1000000100, 0000001100, 1000001100, 0000100100, 0000101100, 0000000110, 1000000110, 0000100110, 0100000100, 0100100100, 0100000110, 0100100110, 0001000000, 1001000000, 0001010000, 0001000001, 1001000001, 0001010001, 0001001000, 1001001000, 0001011000, 0101000000, 0101010000, 0101000001, 0101010001, 0001000100, 1001000100, 0001001100, 1001001100, 0101000100}
Note

When loading the data in the binary format, bit string length information bitlength is required.

For the SumProductTree type output, we can use save_sumproduct and load_sumproduct to save and load serialized data.

all_independent_sets_tree = solve(problem, ConfigsAll(; tree_storage=true))[]

save_sumproduct(filename, all_independent_sets_tree)

loaded_sets_tree = load_sumproduct(filename)
+ (count = 76.0)
├─ + (count = 75.0)
│  ├─ + (count = 71.0)
│  │  ├─ + (count = 67.0)
│  │  │  ├─ + (count = 58.0)
│  │  │  │  ├─ + (count = 54.0)
│  │  │  │  │  ⋮
│  │  │  │  │  
│  │  │  │  └─ * (count = 4.0)
│  │  │  │     ⋮
│  │  │  │     
│  │  │  └─ * (count = 9.0)
│  │  │     ├─ * (count = 9.0)
│  │  │     │  ⋮
│  │  │     │  
│  │  │     └─ * (count = 1.0)
│  │  │        ⋮
│  │  │        
│  │  └─ * (count = 4.0)
│  │     ├─ * (count = 4.0)
│  │     │  ├─ * (count = 4.0)
│  │     │  │  ⋮
│  │     │  │  
│  │     │  └─ * (count = 1.0)
│  │     │     ⋮
│  │     │     
│  │     └─ * (count = 1.0)
│  │        ├─ OnehotVec{10, 2}(2, 1)
│  │        └─ * (count = 1.0)
│  │           ⋮
│  │           
│  └─ * (count = 4.0)
│     ├─ * (count = 4.0)
│     │  ├─ * (count = 4.0)
│     │  │  ├─ * (count = 2.0)
│     │  │  │  ⋮
│     │  │  │  
│     │  │  └─ + (count = 2.0)
│     │  │     ⋮
│     │  │     
│     │  └─ * (count = 1.0)
│     │     ├─ OnehotVec{10, 2}(4, 1)
│     │     └─ OnehotVec{10, 2}(4, 1)
│     └─ * (count = 1.0)
│        ├─ * (count = 1.0)
│        │  ├─ OnehotVec{10, 2}(8, 1)
│        │  └─ OnehotVec{10, 2}(8, 1)
│        └─ * (count = 1.0)
│           ├─ OnehotVec{10, 2}(4, 1)
│           └─ OnehotVec{10, 2}(4, 1)
└─ * (count = 1.0)
   ├─ * (count = 1.0)
   │  ├─ * (count = 1.0)
   │  │  ├─ * (count = 1.0)
   │  │  │  ├─ * (count = 1.0)
   │  │  │  │  ⋮
   │  │  │  │  
   │  │  │  └─ OnehotVec{10, 2}(8, 1)
   │  │  └─ * (count = 1.0)
   │  │     ├─ OnehotVec{10, 2}(2, 1)
   │  │     └─ OnehotVec{10, 2}(8, 1)
   │  └─ * (count = 1.0)
   │     ├─ OnehotVec{10, 2}(4, 1)
   │     └─ OnehotVec{10, 2}(4, 1)
   └─ * (count = 1.0)
      ├─ * (count = 1.0)
      │  ├─ OnehotVec{10, 2}(2, 1)
      │  └─ * (count = 1.0)
      │     ├─ OnehotVec{10, 2}(8, 1)
      │     └─ OnehotVec{10, 2}(8, 1)
      └─ * (count = 1.0)
         ├─ OnehotVec{10, 2}(4, 1)
         └─ OnehotVec{10, 2}(4, 1)

Loading solutions to python

The following python script loads and unpacks the solutions as a numpy array from a :binary format file.

import numpy as np

def loadfile(filename:str, bitlength:int):
    C = int(np.ceil(bitlength / 64))
    arr = np.fromfile(filename, dtype="uint8")
    # Some axes should be transformed from big endian to little endian
    res = np.unpackbits(arr).reshape(-1, C, 8, 8)[:,::-1,::-1,:]
    res = res.reshape(-1, C*64)[:, :(64*C-bitlength)-1:-1]
    print("number of solutions = %d"%(len(res)))
    return res  # in big endian format

res = loadfile(filename, 10)
Note

Check section Maximal independent set problem for solution space properties related the maximal independent sets. That example also contains using cases of finding solution space properties related to minimum sizes:

  • SizeMin for finding minimum several set sizes,
  • CountingMin for counting minimum several set sizes,
  • SingleConfigMin for finding one solution with minimum several sizes,
  • ConfigsMin for enumerating solutions with minimum several sizes,

This page was generated using Literate.jl.