def make_case(name, nb_diracs, dim): # default domain if name == "random": positions = np.random.rand(nb_diracs, dim) elif name == "grid": positions = make_grid(nb_diracs, dim) elif name == "grid_with_rand": positions = make_grid(nb_diracs, dim, rand_val=1) elif name == "faces": # voronoi with 100 points pd = PowerDiagram(np.random.rand(5, dim)) # quantization lot = OptimalTransport(positions=make_grid(nb_diracs, dim)) lot.obj_max_dw = 1e-5 lot.verbosity = 1 for ratio in [1 - 0.85**n for n in range(50)]: # density img_size = 1000 img_points = [] items = [range(img_size) for i in range(dim)] for i in itertools.product(*items): img_points.append(i) img = pd.distances_from_boundaries( np.array(img_points) / img_size).reshape((img_size, img_size)) img = (1 - ratio) + ratio * np.exp(-(100 * img)**2) lot.set_domain(ScaledImage([0, 0], [1, 1], img / np.mean(img))) # opt for _ in range(10): lot.adjust_weights() B = lot.get_centroids() lot.set_positions(lot.get_positions() + 0.3 * (B - lot.get_positions())) positions = lot.get_positions() plt.plot(positions[:, 0], positions[:, 1], ".") plt.show() np.save("/data/{}_n{}_d{}_voro.npy".format(name, nb_diracs, dim), (positions[:, 0], positions[:, 1])) # solve if nb_diracs < 32000000: ot = OptimalTransport(positions) # ot.verbosity = 1 # solve ot.adjust_weights() # display # ot.display_vtk( "results/pd.vtk" ) np.save("/data/{}_n{}_d{}.npy".format(name, nb_diracs, dim), (positions[:, 0], positions[:, 1], ot.get_weights()))
def fit_transport_plans(self, point_clouds, masses=None, rescaling=True, maxerr=1e-6, maxiter=20, t_init=1., *args, **kwargs): """ Fits transport plans to point clouds. Args: point_clouds (dict): dictionary of point clouds masses (dict): dictionary of masses assigned to each point cloud (default will be uniform masses for each point cloud) rescaling (bool): rescale or not the coordinates of point clouds to fit in [0, 1]² to make computations easier (rescaling undone when returning transport plans) maxerr (float): threshold error under which Newton's algo stops maxiter (int): threshold iteration under which Newton's algo stops t_init (float): inital value of t for Newton's algorithm """ nb_clouds = len(point_clouds) cloud_keys = list(point_clouds.keys()) # compute the transport plan of each cloud self.potentials = {} self.transport_plans = np.zeros((nb_clouds, 2 * self.grid_size**2)) for c in range(nb_clouds): # get point cloud sample = point_clouds[cloud_keys[c]].astype('float64') N = len(sample) if rescaling: # rescale to [0, 1]² sample_min, sample_max = np.min(sample, axis=0), np.max(sample, axis=0) sample = (sample - sample_min) / (sample_max - sample_min) # build target measure if masses is not None: nu = masses[cloud_keys[c]] else: nu = np.ones(N)/N # compute OT between source and target (get Kantorovich potentials) self.potentials[c] = newton_ot(self.domain, sample, nu, psi0=None, verbose=False, maxerr=maxerr, maxiter=maxiter, t_init=t_init) # build the *discretized* transport plan associated to these potentials pd = PowerDiagram(sample, -self.potentials[c], self.domain) img = pd.image_integrals([0, 0], [1, 1], [self.grid_size, self.grid_size]) img /= np.expand_dims(img[ :, :, 2], -1) if rescaling: # undo rescaling img[:, :, :2] = (sample_max - sample_min) * img[:, :, :2] + sample_min # save transport plan self.transport_plans[c] = img[:, :, :2].flatten()
def setUp(self): rf = RadialFuncArfd( lambda r: ((1 - r * r) * (r < 1))**2.5, # value lambda w: 1 / w**0.5, # input scaling lambda w: w**2.5, # output scaling lambda r: 2.5 * ((1 - r * r) * (r < 1))**1.5, # value for the der wrt weight lambda w: 1 / w**0.5, # input scaling for the der wrt weight lambda w: w**1.5, # output scaling for the der wrt weight [1], # stops (radii values where we may have discontinuities) 1e-8 # precision ) # set up a domain, with only 1 dirac domain = ConvexPolyhedraAssembly() domain.add_box([0.0, 0.0], [2.0, 1.0]) self.pd = PowerDiagram(domain=domain, radial_func=rf)
def test_unit(self): pd = PowerDiagram(domain=self.domain) pd.set_positions([[0.0, 0.0]]) pd.set_weights([0.0]) areas = pd.integrals() self.assertAlmostEqual(areas[0], 1.0) centroids = pd.centroids() self.assertAlmostEqual(centroids[0][0], 0.5) self.assertAlmostEqual(centroids[0][1], 0.5)
def setUp(self): rf = RadialFuncArfd( lambda r: (1 - r * r) * (r < 1), # value lambda w: 1 / w**0.5, # input (radius) scaling lambda w: w, # output scaling lambda r: r < 1, # value for the der wrt weight lambda w: 1 / w**0.5, # input scaling for the der wrt weight lambda w: 1, # output scaling for the der wrt weight [1] # stops (radii value where we may have discontinuities) ) # should use only 2 polynomials self.assertEqual(rf.nb_polynomials(), 2) # set up a domain, with only 1 dirac domain = ConvexPolyhedraAssembly() domain.add_box([0.0, 0.0], [2.0, 1.0]) self.pd = PowerDiagram(domain=domain, radial_func=rf)
def tg(position, w, eps, ei, ec): pd = PowerDiagram(radial_func=RadialFuncEntropy(eps), domain=self.domain) pd.set_positions([position]) pd.set_weights([w]) res = pd.integrals() self.assertAlmostEqual(res[0], ei, 5) res = pd.centroids() self.assertAlmostEqual(res[0][0], ec[0], 5) self.assertAlmostEqual(res[0][1], ec[1], 5)
def laguerre_areas(domain, Y, psi, der=False): """ Computes the areas of the Laguerre cells intersected with the domain. Args: domain (pysdot.domain_types): domain of the (continuous) source measure Y (np.array): points of the (discrete) target measure psi (np.array or list): Kantorovich potentials der (bool): wether or not return the Jacobian of the areas w.r.t. psi Returns: pd.integrals() (list): list of areas of Laguerre cells """ pd = PowerDiagram(Y, -psi, domain) if der: N = len(psi) mvs = pd.der_integrals_wrt_weights() return mvs.v_values, csr_matrix( (-mvs.m_values, mvs.m_columns, mvs.m_offsets), shape=(N, N)) else: return pd.integrals()
def test_sum_area(self, nb_diracs=100): for _ in range(10): # diracs pd = PowerDiagram(domain=self.domain) pd.set_positions(np.random.rand(nb_diracs, 3)) pd.set_weights(np.ones(nb_diracs)) # integrals areas = pd.integrals() self.assertAlmostEqual(np.sum(areas), 1.0)
def _test_der(self, positions, weights, rf): pd = PowerDiagram(self.domain, rf) pd.set_positions(np.array(positions, dtype=np.double)) pd.set_weights(np.array(weights, dtype=np.double)) pd.display_vtk("der_int.vtk") num = pd.der_integrals_wrt_weight_and_positions() print("------------", num.error) if num.error: return ndi = len(positions) mat = np.zeros((ndi, ndi)) for i in range(ndi): for o in range(num.m_offsets[i + 0], num.m_offsets[i + 1]): mat[i, num.m_columns[o]] = num.m_values[o] print("------------", mat)
def test_integrals(self): # diracs rd = 2.0 pd = PowerDiagram(domain=self.domain, radial_func=RadialFuncPpWmR2()) pd.set_positions(np.array([[1.0, 0.0], [5.0, 5.0]])) pd.set_weights(np.array([rd**2, rd**2])) # integrals ig = pd.integrals() # Integrate[ Integrate[ ( 4 - ( x * x + y * y ) ) * UnitStep[ 2^2 - x^2 - y^2 ] , { x, -1, 2 } ], { y, 0, 3 } ] self.assertAlmostEqual(ig[0], 10.97565662) self.assertAlmostEqual(ig[1], 8 * np.pi) # centroids ct = pd.centroids() # Integrate[ Integrate[ x * ( 4 - ( x * x + y * y ) ) * UnitStep[ 2^2 - x^2 - y^2 ] , { x, -1, 2 } ], { y, 0, 3 } ] self.assertAlmostEqual(ct[0][0], 1.18937008) self.assertAlmostEqual(ct[0][1], 0.69699702) self.assertAlmostEqual(ct[1][0], 5) self.assertAlmostEqual(ct[1][1], 5)
from pysdot.domain_types import ConvexPolyhedraAssembly from pysdot import PowerDiagram import numpy as np positions = np.random.rand( 30, 2 ) domain = ConvexPolyhedraAssembly() domain.add_box([-1, -1], [2, 2]) # diracs pd = PowerDiagram( positions, domain = domain ) pd.add_replication( [ +1, 0 ] ) pd.add_replication( [ -1, 0 ] ) pd.display_vtk( "pb.vtk" )
from pysdot.domain_types import ConvexPolyhedraAssembly from pysdot.radial_funcs import RadialFuncInBall from pysdot import OptimalTransport from pysdot import PowerDiagram import pylab as plt import numpy as np import unittest domain = ConvexPolyhedraAssembly() domain.add_box([0, 0], [1, 1]) positions = [ [ 0.25, 0.5 ], [ 0.75, 0.5 ] ] weights = [ 0.25**2, 0.25**2 ] pd = PowerDiagram( positions, weights, domain, radial_func=RadialFuncInBall()) img = pd.image_integrals( [ 0, 0 ], [ 1, 1 ], [ 100, 100 ] ) img[ :, :, 0 ] *= 1e4 img[ :, :, 1 ] *= 1e4 # for d in range( 3 ): # plt.subplot( 1, 3, d + 1 ) # plt.imshow( img[ :, :, d ] ) # plt.colorbar() # plt.show() # w = 0.1 # print( np.pi * w )
from pysdot.domain_types import ConvexPolyhedraAssembly from pysdot import PowerDiagram import matplotlib.pyplot as plt import numpy as np positions = np.array( [ [ 0.0, 0.5 ], [ 1.0, 0.5 ], ] ) domain = ConvexPolyhedraAssembly() domain.add_box([0, 0], [1, 1]) # diracs pd = PowerDiagram( positions, domain = domain ) l = [] for i in range( 10000 ): l.append( pd.centroids( 0.5 ) ) l = np.vstack( l ) plt.plot( l[ :, 0 ], l[ :, 1 ], '.' ) plt.show()
def _test_der(self, positions, weights, rf): pd = PowerDiagram(self.domain, rf) pd.set_positions(np.array(positions, dtype=np.double)) pd.set_weights(np.array(weights, dtype=np.double)) num = pd.der_integrals_wrt_weights() if num.error: return ndi = len(positions) mat = np.zeros((ndi, ndi)) for i in range(ndi): for o in range(num.m_offsets[i + 0], num.m_offsets[i + 1]): mat[i, num.m_columns[o]] = num.m_values[o] eps = 1e-6 res = pd.integrals() delta = np.max(np.abs(mat)) * 200 * eps for i in range(ndi): pd.set_weights( np.array([weights[j] + eps * (i == j) for j in range(ndi)])) des = pd.integrals() der = (des - res) / eps for j in range(ndi): self.assertAlmostEqual(mat[i, j], der[j], delta=delta)
class TestArfd_2D_1p5(unittest.TestCase): def setUp(self): rf = RadialFuncArfd( lambda r: ((1 - r * r) * (r < 1))**2.5, # value lambda w: 1 / w**0.5, # input scaling lambda w: w**2.5, # output scaling lambda r: 2.5 * ((1 - r * r) * (r < 1))**1.5, # value for the der wrt weight lambda w: 1 / w**0.5, # input scaling for the der wrt weight lambda w: w**1.5, # output scaling for the der wrt weight [1], # stops (radii values where we may have discontinuities) 1e-8 # precision ) # set up a domain, with only 1 dirac domain = ConvexPolyhedraAssembly() domain.add_box([0.0, 0.0], [2.0, 1.0]) self.pd = PowerDiagram(domain=domain, radial_func=rf) def test_integrals(self): self.pd.set_positions(np.array([[0.0, 0.0]])) # weights and expected values (w = weight, i = integral, c = centroid) l = [ { "w": 10.0, "i": 417.0399, "c": [0.815858, 0.476057] }, { "w": 20.0, "i": 2902.3809, "c": [0.911708, 0.488773] }, { "w": 100.0, "i": 191826.6661, "c": [0.983124, 0.497884] }, ] # NumberForm[ N[ Integrate[ Integrate[ ( 10 - ( x * x + y * y ) ) ^ 2.5, { x, 0, 2 } ], { y, 0, 1 } ], 10 ], 10 ] => 417.0399438275571 # NumberForm[ N[ Integrate[ Integrate[ ( 20 - ( x * x + y * y ) ) ^ 2.5, { x, 0, 2 } ], { y, 0, 1 } ], 10 ], 10 ] => 2902.3809 # NumberForm[ N[ Integrate[ Integrate[ ( 100 - ( x * x + y * y ) ) ^ 2.5, { x, 0, 2 } ], { y, 0, 1 } ], 10 ], 10 ] => 191826.6661 # NumberForm[ N[ Integrate[ Integrate[ x * ( 10 - ( x * x + y * y ) ) ^ 2.5, { x, 0, 2 } ], { y, 0, 1 } ] / Integrate[ Integrate[ ( 10 - ( x * x + y * y ) ) ^ 2.5, { x, 0, 2 } ], { y, 0, 1 } ], 10 ], 10 ] # NumberForm[ N[ Integrate[ Integrate[ y * ( 10 - ( x * x + y * y ) ) ^ 2.5, { x, 0, 2 } ], { y, 0, 1 } ] / Integrate[ Integrate[ ( 10 - ( x * x + y * y ) ) ^ 2.5, { x, 0, 2 } ], { y, 0, 1 } ], 10 ], 10 ] # NumberForm[ N[ Integrate[ Integrate[ x * ( 20 - ( x * x + y * y ) ) ^ 2.5, { x, 0, 2 } ], { y, 0, 1 } ] / Integrate[ Integrate[ ( 20 - ( x * x + y * y ) ) ^ 2.5, { x, 0, 2 } ], { y, 0, 1 } ], 10 ], 10 ] # NumberForm[ N[ Integrate[ Integrate[ y * ( 20 - ( x * x + y * y ) ) ^ 2.5, { x, 0, 2 } ], { y, 0, 1 } ] / Integrate[ Integrate[ ( 20 - ( x * x + y * y ) ) ^ 2.5, { x, 0, 2 } ], { y, 0, 1 } ], 10 ], 10 ] # NumberForm[ N[ Integrate[ Integrate[ x * ( 100 - ( x * x + y * y ) ) ^ 2.5, { x, 0, 2 } ], { y, 0, 1 } ] / Integrate[ Integrate[ ( 100 - ( x * x + y * y ) ) ^ 2.5, { x, 0, 2 } ], { y, 0, 1 } ], 10 ], 10 ] # NumberForm[ N[ Integrate[ Integrate[ y * ( 100 - ( x * x + y * y ) ) ^ 2.5, { x, 0, 2 } ], { y, 0, 1 } ] / Integrate[ Integrate[ ( 100 - ( x * x + y * y ) ) ^ 2.5, { x, 0, 2 } ], { y, 0, 1 } ], 10 ], 10 ] # test integrals and centroids for d in l: self.pd.set_weights(np.array([d["w"]])) ig = self.pd.integrals() self.assertAlmostEqual(ig[0], d["i"], places=2) cs = self.pd.centroids() for (v, e) in zip(cs[0], d["c"]): self.assertAlmostEqual(v, e, delta=1e-3) def test_derivatives(self): self.pd.set_positions(np.array([[0.0, 0.0], [1.0, 0.0]])) self.pd.set_weights(np.array([1.0, 2.0])) check_ders(self, self.pd)
def test_derivatives(self): # diracs rd = 2.0 weights = np.array([rd**2, rd**2]) pd = PowerDiagram(domain=self.domain, radial_func=RadialFuncPpWmR2()) pd.set_positions(np.array([[1.0, 0.0], [5.0, 5.0]])) pd.set_weights(weights.copy()) # derivatives num = pd.der_integrals_wrt_weights() ndi = pd.weights.shape[0] mat = np.zeros((ndi, ndi)) for i in range(ndi): for o in range(num.m_offsets[i + 0], num.m_offsets[i + 1]): mat[i, num.m_columns[o]] = num.m_values[o] # numerical eps = 1e-6 res = pd.integrals() delta = np.max(np.abs(mat)) * 100 * eps for i in range(ndi): pd.set_weights( np.array([weights[j] + eps * (i == j) for j in range(ndi)])) des = pd.integrals() der = (des - res) / eps for j in range(ndi): #self.assertAlmostEqual(mat[i, j], der[j], delta=delta) print(mat[i, j], der[j])
from pysdot.domain_types import ConvexPolyhedraAssembly from pysdot import PowerDiagram import numpy as np positions = np.array([[0.25, 0.5], [0.75, 0.5]]) # domain = ConvexPolyhedraAssembly() # domain.add_box( [ 0, 0 ], [ 0.5, 1 ], 1 ) # domain.add_box( [ 0.5, 0 ], [ 1, 1 ], 0.1 ) # diracs pd = PowerDiagram(positions) print(np.sum(pd.second_order_moments())) positions[0, 0] = 0.0 pd = PowerDiagram(positions) print(np.sum(pd.second_order_moments()))
from pysdot import PowerDiagram import pylab as plt import numpy as np positions = np.random.rand(10, 2) # diracs pd = PowerDiagram(positions) points = [] for y in np.linspace(0, 1, 100): for x in np.linspace(0, 1, 100): points.append([x, y]) dist = pd.distances_from_boundaries(np.array(points)) dist = dist.reshape((100, 100)) print(dist.shape) plt.imshow(dist) plt.colorbar() plt.show()
class TestArfd_2D(unittest.TestCase): def setUp(self): rf = RadialFuncArfd( lambda r: (1 - r * r) * (r < 1), # value lambda w: 1 / w**0.5, # input (radius) scaling lambda w: w, # output scaling lambda r: r < 1, # value for the der wrt weight lambda w: 1 / w**0.5, # input scaling for the der wrt weight lambda w: 1, # output scaling for the der wrt weight [1] # stops (radii value where we may have discontinuities) ) # should use only 2 polynomials self.assertEqual(rf.nb_polynomials(), 2) # set up a domain, with only 1 dirac domain = ConvexPolyhedraAssembly() domain.add_box([0.0, 0.0], [2.0, 1.0]) self.pd = PowerDiagram(domain=domain, radial_func=rf) def test_integrals(self): self.pd.set_positions(np.array([[0.0, 0.0]])) # weights and expected values (w = weight, i = integral, c = centroid) l = [ { "w": 0.5, "i": np.pi / 32, "c": [8 * 2**0.5 / (15 * np.pi)] * 2 }, { "w": 1, "i": np.pi / 8, "c": [16.0 / (15 * np.pi)] * 2 }, { "w": 10, "i": 50 / 3, "c": [23.0 / 25, 49.0 / 100] }, { "w": 100, "i": 590 / 3, "c": [293.0 / 295, 589.0 / 1180] }, ] # test integrals and centroids for d in l: self.pd.set_weights(np.array([d["w"]])) ig = self.pd.integrals() self.assertAlmostEqual(ig[0], d["i"], places=5) cs = self.pd.centroids() for (v, e) in zip(cs[0], d["c"]): self.assertAlmostEqual(v, e, places=5) def test_derivatives(self): self.pd.set_positions(np.array([[0.0, 0.0], [1.0, 0.0]])) self.pd.set_weights(np.array([1.0, 2.0])) check_ders(self, self.pd)