예제 #1
0
def do_search(G, X, n_colors, Cso):
    """Local search around X using sum(|B[i]||C[i]| - |C[i]|^2) objective
    """
    
    for n in G:
        for n1 in G[n]:
            assert n in G[n1], '%d %d' % (n, n1)

    def makeX():  
        X1 = [-1] * len(X)
        for c, cls in enumerate(color_classes):
            for x in cls:
                X1[x] = c
        return X1 
    
    # color_classes[c] = nodes with color c
    color_classes = [set([n for n, x in enumerate(X) if x == c]) for c in range(n_colors)]
    assert sum(len(cls) for cls in color_classes) == len(X)
    
    # broken_classes[c] = edges where both colors are c
    broken_classes = [set([]) for c in range(n_colors)] 
    
    # We only need counts for our objective functions
    n_cc = [len(color_classes[c]) for c in range(n_colors)]
    n_bc = [len(broken_classes[c]) for c in range(n_colors)]
            
    def objective(n_cc, n_bc):
        return sum((2 * n_cc[c] * n_bc[c] - n_cc[c] ** 2) for c in range(n_colors))
    
    v = objective(n_cc, n_bc)  
    LEN = 10000
    solutions = SortedDeque([(v, normalize(X), n_cc, n_bc)], LEN)
    tested = set()
    counter = count()
    best_v = v
    best_X = tuple(X)
    best_n_col = len([x for x in n_cc if x > 0])
    
    normX = normalize(X)
    print 'best_X', v, best_n_col, color_counts(normX, n_colors), normX
    
    needs_perturbation = False
    
    while solutions: 
        v, X, n_cc, n_bc = solutions.popleft()
        check_counts(G, n_colors, X, n_cc, n_bc)
예제 #2
0
def solve(n_nodes, n_edges, edges):
    """
        Return chromatic number for graph
        n_nodes:number of nodes in graph
        n_edges: number of edges in graph
        edges: list of all edges 
        Returns: 
            number of colors, list of node colors in same order as nodes, optimal?
    """
    # G = node: edges from node
    G = defaultdict(list)
    for n1, n2 in edges:
        G[n1].append(n2)
        G[n2].append(n1)
        
    for n in G:
        G[n] = frozenset(G[n])
        
    Cso = get_Cso(G)    
        
    # Lower and upper bounds on number of colors    
    n_min = len(Cso[0][0])
    n_max = len(G)
    print 'n_min=%d,n_max=%d' % (n_min, n_max)
    
    MAX_SOLUTIONS = 10 * 1000
    MAX_VISITED = 50 * 1000 * 1000 
    assert MAX_VISITED >= 3 * MAX_SOLUTIONS
    
    candidate_solutions = SortedDeque([], MAX_SOLUTIONS)
    optimized_solutions = SortedDeque([], MAX_SOLUTIONS)
    visited_starting, visited_minimum, visited_tested = set([]), set([]), set([])
            
    X = [-1] * len(G)
    X = populate1(G, X, Cso)    
         
    def print_best():
        max_min = 0
        min_k = optimized_solutions[0][0]
        for i, soln in enumerate(optimized_solutions):
            if soln[0] > min_k:
                break 
            max_min = i    
        #print '=' * 80
        #print log_name
        if os.path.exists(log_name):
            shutil.copy(log_name, log_name + '.old')
        with open(log_name , 'wt') as f:
            f.write('VERSION=%d\n' % VERSION)
            f.write('log_name=%s\n' % log_name)
            f.write('n_min=%d,n_max=%d\n' % (n_min, n_max))
            f.write('fraction_changed=%f\n' % fraction_changed)
            fraction_changed
            f.write('candidate_solutions=%d,optimized_solutions=%d\n' % (len(candidate_solutions), 
                len(optimized_solutions)))
            f.write('count=%d,visited_starting=%d,visited_tested=%d,visited_minimum=%d\n' % (count, 
                    len(visited_starting), len(visited_tested), len(visited_minimum)))
            f.write('lowest number colors: %d : %s\n' % (len(optimized_solutions), 
                [optimized_solutions[i][0:3] for i in range(min(len(optimized_solutions), 50))]))
            f.write('best solutions: %d of %d\n' % (max_min + 1, len(optimized_solutions)))
            for i in range(max_min + 1):
                X = optimized_solutions[i][-1]
                optimal = len(set(X)) == n_min
                f.write('%3d: %s: %s\n' % (i, optimal, optimized_solutions[i]))
                
    n_colors = len(G)
    last_report_time = time.time()
    #while len(solutions) < MAX_SOLUTIONS:
    
    for i, X in enumerate(previous_X):
        hX = hash(normalize(X))
        if hX not in visited_minimum:
            add_solution(optimized_solutions, G, X, -1000 - i) 
            visited_minimum.add(hX)
     
    print '^^^', len(optimized_solutions), len(visited_minimum)
    
    fraction_changed = 0.33
    for count in xrange(10**9):   
        
        if count % 100 == 0:
            fraction_changed = 0.33
        
        fraction_changed *= 0.9
        if fraction_changed < 0.05:
            fraction_changed = 0.05
       
        for visited in visited_starting, visited_minimum, visited_tested :
            if len(visited) >= MAX_VISITED: # 1000 * 1000:
                v1 = len(visited)
                visited = set(list(visited)[(len(visited)*2)//3:])
                v2 = len(visited)
                visited = visited | set(s[-2] for s in optimized_solutions)
                print 'reseting visited', v1, v2, len(visited)
            
        #if len(solutions) % 1000 == 2:
        if time.time() > last_report_time + 60:
            print_best()
            last_report_time = time.time()
        
        #X = do_kempe(G, X)
        
        # Replenish candidate_solutions
        target_score = candidate_solutions[0][0] if candidate_solutions else 0
        candidate_index = 0
        for ii in range(1000):
            while True: 
                X = repopulate(G, visited_starting, X, Cso, target_score, visited_minimum, fraction_changed)  
                if X is None:
                    print '!! Repopulate failed !!!', candidate_index, len(candidate_solutions)
                    candidate_index += 1  
                    target_score = candidate_solutions[candidate_index][0]
                    X = candidate_solutions[candidate_index][-1]
                    continue
                hX = hash(X)
                if hX not in visited_minimum and hX not in visited_tested:
                    break
                print 'repopulating'  
                
            add_solution(candidate_solutions, G, X, count)        
            nn = len(set(X)) 
            if len(candidate_solutions) >= 10 and (nn <= target_score or ii >= 10):
                break  
            #print ('~', len(set(X))),
            print (len(candidate_solutions), nn) ,
        print '.',   
        
        # Take best candidate solution
        while candidate_solutions:
            soln = candidate_solutions.popleft()
            # solution = (n_colors, score, count, hash(nX), nX)
            if soln[3] not in visited_tested and soln[3] not in visited_minimum:
                X = soln[-1]
                break
        visited_tested.add(soln[3])  
        print soln[0], ':', fraction_changed
            
        optimal = len(set(set(X))) == n_min
        if not optimal:
            X_list = do_search(G, visited_minimum, X)
            for X in X_list:
                n_col = len(set(X))
                optimal = n_col == n_min
                #print 'i=%d,optimal=%s' % (len(solutions), optimal)
                add_solution(optimized_solutions, G, X, count)
                add_solution(candidate_solutions, G, X, count)
                if n_col < n_colors:
                    print 'n_colors %d => %d, count=%d, visited=%s, solutions=%s, fraction_changed=%f' % (n_colors, 
                        n_col, count, 
                        (len(visited_starting), len(visited_tested), len(visited_minimum)),
                        (len(candidate_solutions), len(optimized_solutions)),
                        fraction_changed)
                    n_colors = n_col
                if optimal:
                    break    
        if optimal:
            break
            
        if len(optimized_solutions) >= 1:
            if random.randrange(0, 3) != 0:
                X = optimized_solutions[0][-1]
            else:    
                max_all = len(optimized_solutions) - 1
                max_min = 0
                min_k = optimized_solutions[0][0]
                for i, soln in enumerate(optimized_solutions):
                    if soln[0] > min_k:
                        break
                    max_min = i
                if random.randrange(0, 3) != 0:
                    max_i = max_min
                else:
                    max_i = max_all
                X = optimized_solutions[random.randrange(0, max_i+1)][-1]    
            
         
            
       
        #visited = [hash(s[1]) for s in solutions]
       
        if False:
            print '------------'
            print 'solutions', len(solutions), [(solutions[i][0], 
                        (solutions[i][2], len(solutions)-solutions[i][2] -1), hash(s[1])) 
                            for i in range(min(len(solutions), 40))]
            print 'visited', len(visited), visited   

        
            
        
    
    print '*^*Done'
    print_best()
        
    exit()    
         
    for n in G:
        assert X[n] >= 0, '%d %s' % (n, G[n])
        assert all(X[n] != X[n1] for n1 in G[n]), '\n%d %s\n%d %s' % (
            n, G[n], X[n], [X[n1] for n1 in G[n]] ) 
    
    for n in G:
        print n, X[n], G[n], [X[i] for i in G[n]]
        
    print len(set(X)), optimal    
    print '+' * 40    
    return len(set(X)), X, optimal
    
    #print G    
    assert len(G) == n_nodes
    #print '-' * 80 
    
    # Nodes by order
    C = [-1] * n_nodes
    C[0] = 0
    
    Q, V = [0], set([])
    while Q:
        n = Q.pop()
        if n in V:
            continue
        V.add(n)
        #print n, G[n],
        for c in count():
         #   print c, 
            if not any(c == C[i] for i in G[n]):
                break
        C[n] = c        
        #print ':', c 
        for m in G[n]:
            Q.append(m)
        
  
    #print '-' * 80            
    #print C  
    #print '=' * 80  
    return len(set(C)), [C[i] for i in range(n_nodes)], True  
예제 #3
0
def solve(n_nodes, n_edges, edges):
    """
        Return chromatic number for graph
        n_nodes:number of nodes in graph
        n_edges: number of edges in graph
        edges: list of all edges 
        Returns: 
            number of colors, list of node colors in same order as nodes, optimal?
    """
    # G = node: edges from node
    G = defaultdict(list)
    for n1, n2 in edges:
        G[n1].append(n2)
        G[n2].append(n1)

    for n in G:
        G[n] = frozenset(G[n])

    Cso = get_Cso(G)

    # Lower and upper bounds on number of colors
    n_min = len(Cso[0][0])
    n_max = len(G)
    print "n_min=%d,n_max=%d" % (n_min, n_max)

    MAX_SOLUTIONS = 10 * 1000
    MAX_VISITED = 1000 * 1000
    assert MAX_VISITED >= 3 * MAX_SOLUTIONS

    candidate_solutions = SortedDeque([], MAX_SOLUTIONS)
    optimized_solutions = SortedDeque([], MAX_SOLUTIONS)
    visited_starting, visited_minimum, visited_tested = set([]), set([]), set([])

    X = [-1] * len(G)
    X = populate1(G, X, Cso)

    def print_best():
        max_min = 0
        min_k = optimized_solutions[0][0]
        for i, soln in enumerate(optimized_solutions):
            if soln[0] > min_k:
                break
            max_min = i
        # print '=' * 80
        # print log_name
        if os.path.exists(log_name):
            shutil.copy(log_name, log_name + ".old")
        with open(log_name, "wt") as f:
            f.write("VERSION=%d\n" % VERSION)
            f.write("log_name=%s\n" % log_name)
            f.write("n_min=%d,n_max=%d\n" % (n_min, n_max))
            f.write(
                "candidate_solutions=%d,optimized_solutions=%d\n" % (len(candidate_solutions), len(optimized_solutions))
            )
            f.write(
                "count=%d,visited_starting=%d,visited_tested=%d,visited_minimum=%d\n"
                % (count, len(visited_starting), len(visited_tested), len(visited_minimum))
            )
            f.write(
                "lowest number colors: %d : %s\n"
                % (
                    len(optimized_solutions),
                    [optimized_solutions[i][0:3] for i in range(min(len(optimized_solutions), 50))],
                )
            )
            f.write("best solutions: %d of %d\n" % (max_min + 1, len(optimized_solutions)))
            for i in range(max_min + 1):
                X = optimized_solutions[i][-1]
                optimal = len(set(X)) == n_min
                f.write("%3d: %s: %s\n" % (i, optimal, optimized_solutions[i]))

    n_colors = len(G)
    last_report_time = time.time()
    # while len(solutions) < MAX_SOLUTIONS:
    for count in xrange(10 ** 9):

        for visited in visited_starting, visited_minimum, visited_tested:
            if len(visited) >= MAX_VISITED:  # 1000 * 1000:
                v1 = len(visited)
                visited = set(list(visited)[(len(visited) * 2) // 3 :])
                v2 = len(visited)
                visited = visited | set(s[-2] for s in solutions)
                print "reseting visited", v1, v2, len(visited)

        # if len(solutions) % 1000 == 2:
        if time.time() > last_report_time + 60:
            print_best()
            last_report_time = time.time()

        # X = do_kempe(G, X)

        # Replenish candidate_solutions

        for ii in range(1000):
            while True:
                X = repopulate(G, visited_starting, X, Cso)
                hX = hash(X)
                if hX not in visited_minimum and hX not in visited_tested:
                    break
                print "repopulating"

            add_solution(candidate_solutions, G, X, count)
            nn = len(set(X))
            if len(candidate_solutions) >= 10 and (nn <= candidate_solutions[0][0] or ii >= 10):
                break
            # print ('~', len(set(X))),
            print (len(candidate_solutions), nn),
        print ".",

        # Take best candidate solution
        while candidate_solutions:
            soln = candidate_solutions.popleft()
            # solution = (n_colors, score, count, hash(nX), nX)
            if soln[3] not in visited_tested and soln[3] not in visited_minimum:
                X = soln[-1]
                break
        visited_tested.add(soln[3])
        print soln[0]

        optimal = len(set(set(X))) == n_min
        if not optimal:
            X = do_search(G, visited_minimum, X)
            n_col = len(set(X))
            optimal = n_col == n_min
            # print 'i=%d,optimal=%s' % (len(solutions), optimal)
            add_solution(optimized_solutions, G, X, count)
            add_solution(candidate_solutions, G, X, count)
            if n_col < n_colors:
                print "n_colors %d => %d, count=%d, visited=%s, solutions=%s" % (
                    n_colors,
                    n_col,
                    count,
                    (len(visited_starting), len(visited_tested), len(visited_minimum)),
                    (len(candidate_solutions), len(optimized_solutions)),
                )
                n_colors = n_col
        if optimal:
            break

        if len(optimized_solutions) >= 1:
            if random.randrange(0, 3) != 0:
                X = optimized_solutions[0][-1]
            else:
                max_all = len(optimized_solutions) - 1
                max_min = 0
                min_k = optimized_solutions[0][0]
                for i, soln in enumerate(optimized_solutions):
                    if soln[0] > min_k:
                        break
                    max_min = i
                if random.randrange(0, 3) != 0:
                    max_i = max_min
                else:
                    max_i = max_all
                X = optimized_solutions[random.randrange(0, max_i + 1)][-1]

        # visited = [hash(s[1]) for s in solutions]

        if False:
            print "------------"
            print "solutions", len(solutions), [
                (solutions[i][0], (solutions[i][2], len(solutions) - solutions[i][2] - 1), hash(s[1]))
                for i in range(min(len(solutions), 40))
            ]
            print "visited", len(visited), visited

    print "*^*Done"
    print_best()

    exit()

    for n in G:
        assert X[n] >= 0, "%d %s" % (n, G[n])
        assert all(X[n] != X[n1] for n1 in G[n]), "\n%d %s\n%d %s" % (n, G[n], X[n], [X[n1] for n1 in G[n]])

    for n in G:
        print n, X[n], G[n], [X[i] for i in G[n]]

    print len(set(X)), optimal
    print "+" * 40
    return len(set(X)), X, optimal

    # print G
    assert len(G) == n_nodes
    # print '-' * 80

    # Nodes by order
    C = [-1] * n_nodes
    C[0] = 0

    Q, V = [0], set([])
    while Q:
        n = Q.pop()
        if n in V:
            continue
        V.add(n)
        # print n, G[n],
        for c in count():
            #   print c,
            if not any(c == C[i] for i in G[n]):
                break
        C[n] = c
        # print ':', c
        for m in G[n]:
            Q.append(m)

    # print '-' * 80
    # print C
    # print '=' * 80
    return len(set(C)), [C[i] for i in range(n_nodes)], True
예제 #4
0
def do_search(G, X, n_colors):
    """Local search around X using sum(|B[i]||C[i]| - |C[i]|^2) objective
    """
    
    for n in G:
        for n1 in G[n]:
            assert n in G[n1], '%d %d' % (n, n1)

    def makeX():  
        X1 = [-1] * len(X)
        for c, cls in enumerate(color_classes):
            for x in cls:
                X1[x] = c
        return X1 
    
    # color_classes[c] = nodes with color c
    color_classes = [set([n for n, x in enumerate(X) if x == c]) for c in range(n_colors)]
    assert sum(len(cls) for cls in color_classes) == len(X)
    
    # broken_classes[c] = edges where both colors are c
    broken_classes = [set([]) for c in range(n_colors)] 
    
    # We only need counts for our objective functions
    n_cc = [len(color_classes[c]) for c in range(n_colors)]
    n_bc = [len(broken_classes[c]) for c in range(n_colors)]
            
    def objective(n_cc, n_bc):
        return sum((2 * n_cc[c] * n_bc[c] - n_cc[c] ** 2) for c in range(n_colors))
        
    #def delta(n, c, n_cc_c0, n_cc_c, n_bc_c0, n_bc_c):
    #    c0 = X(G[n])
    #    before = 2 * n_cc_c0 * n_bc_c0 - n_cc_c0**2
    #    n_cc_c0 -= 1
    #    n_cc_c += 1
    #    n_bc_c0 -= sum((int(X(G[n1]) == c0) for n1 in G[n])
    #    n_bc_c  += sum((int(X(G[n1]) == c)  for n1 in G[n])
    #    after = 2 * n_cc_c0 * n_bc_c0 - n_cc_c0**2
    #    return after - before
    
    v = objective(n_cc, n_bc)  
    LEN = 10000
    solutions = SortedDeque([(v, tuple(X), n_cc, n_bc)], LEN)
    tested = set()
    counter = count()
    best_v = v
    best_X = tuple(X)
    best_n_col = len([x for x in n_cc if x > 0])
    
    normX = normalize(X)
    print 'best_X', v, best_n_col, color_counts(normX), normX
    
    while solutions: 
        v, X, n_cc, n_bc = solutions.pop()
        if hash(X) in tested:
            continue
          
        tested.add(hash(X))    
        #assert v == objective(n_cc, n_bc)
        n_col = len([x for x in n_cc if x > 0])
        print '*', v, n_col, len(solutions), len(tested), best_n_col #, X, n_cc, n_bc
        if False:
            if len(tested) % 100 == 1:
                print X
                print n_cc
                print n_bc
                validate(G, X)
            
        if n_col < best_n_col or (n_col == best_n_col and v < best_v):
            if n_col < best_n_col:    
                normX = normalize(X)
                print 'best_X', v, n_col, color_counts(normX), normX
                validate(G, X)
            best_v = v
            best_X = X[:]
            best_n_col = n_col

            
        for n in G:
            c0 = X[n]
            for c in range(n_colors):
                # Looking for a new color
                if c == c0:
                    continue
                #X2[n] = c
                #d = delta(n, c, n_cc[c0], n_cc[c], n_bc[c0], n_bc[c])
                c0 = X[n]
                # Can't remove any c0 color nodes if none exist
                if n_cc[c0] == 0:
                    continue
                n_cc_c0, n_cc_c, n_bc_c0, n_bc_c = n_cc[c0], n_cc[c], n_bc[c0], n_bc[c]
                before = 2 * n_cc_c0 * n_bc_c0 - n_cc_c0**2 + 2 * n_cc_c * n_bc_c - n_cc_c**2
                n_cc_c0 -= 1
                n_cc_c += 1
                n_bc_c0 -= sum(int(X[n1] == c0) for n1 in G[n])
                n_bc_c  += sum(int(X[n1] == c)  for n1 in G[n])
                after = 2 * n_cc_c0 * n_bc_c0 - n_cc_c0**2 + 2 * n_cc_c * n_bc_c - n_cc_c**2
                #print '&', before, after
                if after < before: # and v + after - before > best_v:
                    X2, n_cc2, n_bc2 = list(X), n_cc[:], n_bc[:]
                    X2[n] = c
                    n_cc2[c0], n_cc2[c], n_bc2[c0], n_bc2[c] =  n_cc_c0, n_cc_c, n_bc_c0, n_bc_c
                    v2 = objective(n_cc2, n_bc2)
                    #assert v2 == v + after - before
                    tX2 = tuple(X2)
                    if hash(tX2) in tested:
                        continue
                    solutions.insert((v + after - before, tX2, n_cc2, n_bc2))

    return best_X