Graphviz 15.1.1~dev.20260630.1303
Loading...
Searching...
No Matches
node_distinct_coloring.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include "config.h"
12
13#include <sparse/general.h>
14#include <sparse/SparseMatrix.h>
15#include <sparse/QuadTree.h>
17#include <edgepaint/lab.h>
19#include <math.h>
21#include <stdbool.h>
22#include <stddef.h>
23#include <string.h>
24#include <util/alloc.h>
25#include <util/debug.h>
26#include <util/gv_math.h>
27#include <util/random.h>
28
29static void node_distinct_coloring_internal2(int scheme, QuadTree qt,
30 bool weightedQ, SparseMatrix A,
31 int cdim, double accuracy,
32 int seed, double *colors,
33 double *color_diff0,
34 double *color_diff_sum0) {
35 /* here we assume the graph is connected. And that the matrix is symmetric */
36 double dist_max;
37 double *cc;
38 int iter = 0;
39 static const int iter_max = 100;
40 double red[3];
41 double black[] = {0, 0, 0};
42
43 assert(accuracy > 0);
44 const int max_level = d2i(fmin(30, fmax(1, -log(accuracy) / log(2.))));
45
46 {
47 color_rgb rgb = { .r = 255*0.5, .g = 0, .b = 0 };
48 color_lab lab = RGB2LAB(rgb);
49 red[0] = lab.l; red[1] = lab.a; red[2] = lab.b;
50 }
51
52 const size_t n = A->m;
53 if (n == 1){
54 if (scheme == COLOR_LAB){
55 assert(qt);
56 QuadTree_get_nearest(qt, black, colors, &(int){0}, &(double){0});
57 LAB2RGB_real_01(colors);
58 *color_diff0 = 1000; *color_diff_sum0 = 1000;
59 } else {
60 for (int i = 0; i < cdim; i++) colors[i] = 0;
61 *color_diff0 = sqrt(cdim); *color_diff_sum0 = sqrt(cdim);
62 }
63 return;
64 } else if (n == 2){
65 if (scheme == COLOR_LAB){
66 assert(qt);
67 QuadTree_get_nearest(qt, black, colors, &(int){0}, &(double){0});
68 LAB2RGB_real_01(colors);
69
70 QuadTree_get_nearest(qt, red, colors+cdim, &(int){0}, &(double){0});
71 LAB2RGB_real_01(colors+cdim);
72 *color_diff0 = 1000; *color_diff_sum0 = 1000;
73
74 } else {
75 for (int i = 0; i < cdim; i++) colors[i] = 0;
76 for (int i = 0; i < cdim; i++) colors[cdim+i] = 0;
77 colors[cdim] = 0.5;
78 *color_diff0 = sqrt(cdim); *color_diff_sum0 = sqrt(cdim);
79 }
80 return;
81 }
82 assert(n == A->m);
83 const int *ia = A->ia;
84 const int *ja = A->ja;
85 const double *const a = A->type == MATRIX_TYPE_REAL ? A->a : NULL;
86
87 /* cube [0, cspace_size]^3: only uised if not LAB */
88 const double cspace_size = 0.7;
89 double center[] = {cspace_size * 0.5, cspace_size * 0.5, cspace_size * 0.5};
90 const double width = cspace_size * 0.5;
91
92 /* randomly assign colors first */
93 srand(seed);
94 for (int i = 0; i < (int)n * cdim; i++) colors[i] = cspace_size*drand();
95
96 double *x = gv_calloc(cdim * n, sizeof(double));
97 double *wgt = weightedQ ? gv_calloc(n, sizeof(double)) : NULL;
98
99 double color_diff = 0;
100 double color_diff_old = -1;
101 double color_diff_sum = 0;
102 double color_diff_sum_old = -1;
103
104 while (iter++ < iter_max && (color_diff > color_diff_old || (color_diff == color_diff_old && color_diff_sum > color_diff_sum_old))){
105 color_diff_old = color_diff;
106 color_diff_sum_old = color_diff_sum;
107 for (size_t i = 0; i < n; i++){
108 int k = 0;
109 for (int j = ia[i]; j < ia[i+1]; j++){
110 if (ja[j] == (int)i) continue;
111 memcpy(&(x[k*cdim]), &(colors[ja[j]*cdim]), sizeof(double)*cdim);
112 if (wgt && a) wgt[k] = a[j];
113 k++;
114 }
115 cc = &(colors[(int)i * cdim]);
116 if (scheme == COLOR_LAB){
117 furtherest_point_in_list(k, cdim, wgt, x, qt, max_level, &dist_max, &cc);
118 } else if (scheme == COLOR_RGB || scheme == COLOR_GRAY){
119 furtherest_point(k, cdim, wgt, x, center, width, max_level, &dist_max, &cc);
120 } else {
121 assert(0);
122 }
123 if (i == 0){
124 color_diff = dist_max;
125 color_diff_sum = dist_max;
126 } else {
127 color_diff = MIN(dist_max, color_diff);
128 color_diff_sum += dist_max;
129 }
130 }
131
132 GV_DEBUG("iter ---- %d ---, color_diff = %f, color_diff_sum = %f", iter,
133 color_diff, color_diff_sum);
134 }
135
136 if (scheme == COLOR_LAB){
137 /* convert from LAB to RGB */
138 for (size_t i = 0; i < n; i++){
139 const color_lab lab = color_lab_init(colors[(int)i * cdim],
140 colors[(int)i * cdim + 1],
141 colors[(int)i * cdim + 2]);
142 const color_rgb rgb = LAB2RGB(lab);
143 colors[(int)i * cdim] = rgb.r /255;
144 colors[(int)i * cdim + 1] = rgb.g / 255;
145 colors[(int)i * cdim + 2] = rgb.b / 255;
146 }
147 }
148 *color_diff0 = color_diff;
149 *color_diff_sum0 = color_diff_sum;
150 free(x);
151 free(wgt);
152}
153
154static void node_distinct_coloring_internal(int scheme, QuadTree qt,
155 bool weightedQ, SparseMatrix A,
156 int cdim, double accuracy,
157 int seed, double *colors) {
158 int i;
159 double color_diff;
160 double color_diff_sum;
161 if (seed < 0) {
162 /* do multiple iterations and pick the best */
163 int iter, seed_max = -1;
164 double color_diff_max = -1;
165 srand(123);
166 iter = -seed;
167 for (i = 0; i < iter; i++){
168 seed = (int)gv_random(100000);
169 node_distinct_coloring_internal2(scheme, qt, weightedQ, A, cdim, accuracy, seed, colors, &color_diff, &color_diff_sum);
170 if (color_diff_max < color_diff){
171 seed_max = seed; color_diff_max = color_diff;
172 }
173 }
174 seed = seed_max;
175 }
176 node_distinct_coloring_internal2(scheme, qt, weightedQ, A, cdim, accuracy, seed, colors, &color_diff, &color_diff_sum);
177
178}
179
180int node_distinct_coloring(const char *color_scheme, int *lightness,
181 bool weightedQ, SparseMatrix A0, double accuracy,
182 int seed, size_t *cdim0, double **colors) {
183 SparseMatrix B, A = A0;
184 size_t ncomps;
185 int *comps = NULL;
186 int nn;
187 int j, jj;
188 QuadTree qt = NULL;
189 int cdim;
190 int scheme = COLOR_LAB;
191 int maxcolors = 10000, max_qtree_level = 10, r, g, b;
192 const char *color_list = color_palettes_get(color_scheme);
193 if (color_list) color_scheme = color_list;
194
195 cdim = 3;
196 *cdim0 = 3;
197 if (strcmp(color_scheme, "lab") == 0){
198 GV_DEBUG("lab");
199 scheme = COLOR_LAB;
200 qt = lab_gamut_quadtree(lightness, max_qtree_level);
201 if (!qt){
202 fprintf(stderr, "out of memory\n");
203 return -1;
204 }
205 } else if (strcmp(color_scheme, "rgb") == 0){
206 GV_DEBUG("rgb");
207 scheme = COLOR_RGB;
208 } else if (strcmp(color_scheme, "gray") == 0){
209 scheme = COLOR_GRAY;
210 cdim = 1;
211 *cdim0 = 1;
212 } else if (sscanf(color_scheme,"#%02X%02X%02X", &r, &g, &b) == 3 ){
213 scheme = COLOR_LAB;
214 double *color_points = color_blend_rgb2lab(color_scheme, maxcolors);
215 assert(color_points);
216 qt = QuadTree_new_from_point_list(cdim, maxcolors, max_qtree_level,
217 color_points);
218 free(color_points);
219 assert(qt);
220 } else {
222 }
223
224
225 if (accuracy <= 0) accuracy = 0.0001;
226
227 const size_t n = A->m;
228 if (n != (size_t)A->n) {
229 QuadTree_delete(qt);
230 return -1;
231 }
232
233 *colors = gv_calloc(cdim * n, sizeof(double));
234 double *ctmp = gv_calloc(cdim * n, sizeof(double));
235
236 B = SparseMatrix_symmetrize(A, false);
237 A = B;
238
239 int *comps_ptr = SparseMatrix_weakly_connected_components(A, &ncomps, &comps);
240
241 for (size_t i = 0; i < ncomps; i++){
242 nn = comps_ptr[i+1] - comps_ptr[i];
243 B = SparseMatrix_get_submatrix(A, nn, nn, &(comps[comps_ptr[i]]), &(comps[comps_ptr[i]]));
244 node_distinct_coloring_internal(scheme, qt, weightedQ, B, cdim, accuracy, seed, ctmp);
245
246 for (j = comps_ptr[i]; j < comps_ptr[i+1]; j++){
247 jj = j - comps_ptr[i];
248 memcpy(&((*colors)[comps[j]*cdim]), &(ctmp[jj*cdim]), cdim*sizeof(double));
249 }
251 }
252 free(comps_ptr);
253 free(ctmp);
254 QuadTree_delete(qt);
255
256 if (A != A0) SparseMatrix_delete(A);
257 free(comps);
258 return 0;
259}
void QuadTree_get_nearest(QuadTree qt, double *x, double *ymin, int *imin, double *min)
Definition QuadTree.c:684
QuadTree QuadTree_new_from_point_list(int dim, int n, int max_level, double *coord)
Definition QuadTree.c:311
void QuadTree_delete(QuadTree q)
Definition QuadTree.c:377
int * SparseMatrix_weakly_connected_components(SparseMatrix A0, size_t *ncomp, int **comps)
SparseMatrix SparseMatrix_get_submatrix(SparseMatrix A, int nrow, int ncol, int *rindices, int *cindices)
SparseMatrix SparseMatrix_symmetrize(SparseMatrix A, bool pattern_symmetric_only)
void SparseMatrix_delete(SparseMatrix A)
@ MATRIX_TYPE_REAL
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
#define MIN(a, b)
Definition arith.h:28
const char * color_palettes_get(const char *color_palette_name)
helpers for verbose/debug printing
#define GV_DEBUG(...)
Definition debug.h:40
static long seed
Definition exeval.c:1010
#define A(n, t)
Definition expr.h:76
void furtherest_point_in_list(int k, int dim, double *wgt, double *pts, QuadTree qt, int max_level, double *dist_max, double **argmax)
void furtherest_point(int k, int dim, double *wgt, double *pts, double *center, double width, int max_level, double *dist_max, double **argmax)
double drand(void)
Definition general.c:24
void free(void *)
node NULL
Definition grammar.y:181
Arithmetic helper functions.
static int d2i(double v)
Definition gv_math.h:157
static const char black[]
#define B
Definition hierarchy.c:120
QuadTree lab_gamut_quadtree(const int *lightness, int max_qtree_level)
construct a quadtree of the LAB gamut points
Definition lab.c:183
void LAB2RGB_real_01(double *color)
Definition lab.c:76
color_lab color_lab_init(double l, double a, double b)
Definition lab.c:38
color_lab RGB2LAB(color_rgb color)
Definition lab.c:64
double * color_blend_rgb2lab(const char *color_list, const int maxpoints)
Definition lab.c:209
color_rgb LAB2RGB(color_lab color)
Definition lab.c:84
static void node_distinct_coloring_internal(int scheme, QuadTree qt, bool weightedQ, SparseMatrix A, int cdim, double accuracy, int seed, double *colors)
static void node_distinct_coloring_internal2(int scheme, QuadTree qt, bool weightedQ, SparseMatrix A, int cdim, double accuracy, int seed, double *colors, double *color_diff0, double *color_diff_sum0)
int node_distinct_coloring(const char *color_scheme, int *lightness, bool weightedQ, SparseMatrix A0, double accuracy, int seed, size_t *cdim0, double **colors)
@ ERROR_BAD_COLOR_SCHEME
size_t gv_random(size_t bound)
Definition random.c:85
random number generation
double b
l: 0 to 100, a,b: -128 to 128
Definition lab.h:24
double a
Definition lab.h:24
double l
Definition lab.h:24
double r
Definition lab.h:14
double g
Definition lab.h:14
double b
Definition lab.h:14
static point center(point vertex[], size_t n)