def compute_data(self): """Compute the convex hull and associated data""" self.edges = set() self.point_edges = [[] for i in range(len(self.points))] self.edge_normals = {} ps = self.points self.planar = len(ps) <= 2 if len(ps) == 1: self.edges.add((0, 0)) #phantom edge self.point_edges[0].append((0, 0)) #only one edge self.edge_normals = {(0, 0): [np.zeros(3), np.zeros(3)]} elif len(ps) == 2: self.edges.add((0, 1)) #unique edge self.point_edges[0].append((0, 1)) #only one edge self.point_edges[1].append((0, 1)) #only one edge #compute the normal of the arc n1 = np.cross(ps[0], ps[1]) if nla.norm(n1) > 1e-7: n1 /= nla.norm(n1) self.edge_normals = {(0, 1): [n1, -n1]} #compute second normal of the arc n2 = ps[0] + ps[1] if nla.norm(n2) > 1e-7: n2 /= nla.norm(n2) self.edge_arc = {(0, 1): (n1, n2, 2 * np.pi)} else: data = [''] try: data = pyhull.qconvex('i FN Fn n -A%1.5f' % self.cos_merge, ps) except: data = [''] if not data[0]: #try the planar convex hull projecting in XY self.planar = True try: data = pyhull.qconvex( 'i FN Fn n Qb0:0B0:0 -A%1.5f' % self.cos_merge, ps) except: data = [''] if not data[0]: #try the planar convex hull projecting in XZ try: data = pyhull.qconvex( 'i FN Fn n Qb1:0B1:0 -A%1.5f' % self.cos_merge, ps) except: data = [''] if not data[0]: #it should never get to this point!!! #try the planar convex hull projecting in YZ data = pyhull.qconvex( 'i FN Fn n Qb2:0B2:0 -A%1.5f' % self.cos_merge, ps) self.parse_data(data)
def test_qconvex(self): data = [[-0.5, -0.5], [-0.5, 0.5], [0.5, -0.5], [0.5, 0.5]] self.assertEqual(['4', '0 2', '1 0', '2 3', '3 1'], qconvex("i", data)) self.assertEqual(['4', '0 2', '1 0', '2 3', '3 1'], qconvex("i Qt", data)) self.assertEqual(qconvex("n", data), [ '3', '4', '-0 -1 -0.5', '-1 0 -0.5', '1 -0 -0.5', '0 1 -0.5' ]) self.assertIsNotNone(qconvex('QR0 FA Pp', data))
def test_qconvex(self): data = [[-0.5, -0.5], [-0.5, 0.5], [0.5, -0.5], [0.5, 0.5]] self.assertEqual(['4', '0 2', '1 0', '2 3', '3 1'], qconvex("i", data)) self.assertEqual(['4', '0 2', '1 0', '2 3', '3 1'], qconvex("i Qt", data)) self.assertEqual(qconvex("n", data), ['3', '4', '-0 -1 -0.5', '-1 0 -0.5', '1 -0 -0.5', '0 1 -0.5']) self.assertIsNotNone(qconvex('QR0 FA Pp', data))
def zonotope_add(V, Sign, normals): # N: normals of the hyperplanes num_normals = normals.shape[0] dim = normals.shape[1] for i in range(num_normals): normal = normals[i] V_ = np.empty((0, dim)) Sign_ = np.empty((0, i + Sign.shape[1])) for k in range(V.shape[0]): v = V[k] v_pm = np.vstack((v + normal, v - normal)) v_sign = np.hstack((np.array([Sign[k], Sign[k]]), [[1], [-1]])) ind_v = [True, True] Sign_ = np.vstack((Sign_, v_sign[ind_v])) V_ = np.vstack((V_, v_pm[ind_v])) # take the convex hull of V_ orth = sp.linalg.orth((V_ - V_[1, :]).T) if orth.shape[1] != V.shape[1]: Vr = np.dot((V_ - V_[1, :]), orth) else: Vr = V_ - V_[1, :] vertices = [list(Vr[i]) for i in range(Vr.shape[0])] ret = pyhull.qconvex('Fx', vertices) ind_vertices = [int(ret[j]) for j in range(1, len(ret))] V = V_[ind_vertices] Sign = Sign_[ind_vertices] return V, Sign
def compute_hiperspaces(self): if not len(self.points) > 0: logger.error('No points to compute hull!') raise Exception('No points to compute hull!') # The heuristic caracteristic when searching to connect # different clusters does that it might fail # so we redirect the stdout to avoid such error # being visible to user stderr_fd = sys.stderr.fileno() with open('/tmp/qhull-output.log', 'w') as f, stderr_redirected(f): points = list(self.points) logger.info('Searching for hull in dimension %s based on %s points', len(points[0]),len(points)) output = qconvex('n',points) if len(output) == 1: logger.debug('Could not get Hull. Joggle input?') try: dim, facets_nbr, facets = self.__parse_hs_output(output) except IncorrectOutput: logger.error('Could not get hull') raise CannotGetHull() logger.info('Found hull in dimension %s of %s facets', dim,facets_nbr) self.dim = dim self.facets = facets return self.dim
def get_lines_voronoi(data): from pyhull import qconvex output = qconvex("o", data) nb_points = int(output[1].split(" ")[0]) list_lines = [] list_points = [] for i in range(2, 2 + nb_points): list_points.append([float(c) for c in output[i].strip().split()]) facets = [] for i in range(2 + nb_points, len(output)): if output[i] != "": tmp = output[i].strip().split(" ") facets.append([int(tmp[j]) for j in range(1, len(tmp))]) for i in range(len(facets)): for line in itertools.combinations(facets[i], 2): for j in range(len(facets)): if i != j and line[0] in facets[j] and line[1] in facets[j]: # check if the two facets i and j are not coplanar vector1 = np.array(list_points[facets[j][0]]) - np.array(list_points[facets[j][1]]) vector2 = np.array(list_points[facets[j][0]]) - np.array(list_points[facets[j][2]]) n1 = np.cross(vector1, vector2) vector1 = np.array(list_points[facets[i][0]]) - np.array(list_points[facets[i][1]]) vector2 = np.array(list_points[facets[i][0]]) - np.array(list_points[facets[i][2]]) n2 = np.cross(vector1, vector2) dot = math.fabs(np.dot(n1, n2) / (np.linalg.norm(n1) * np.linalg.norm(n2))) if 1.05 > dot > 0.95: continue list_lines.append({"start": list_points[line[0]], "end": list_points[line[1]]}) break return list_lines
def convex_hull_volume_pyhull(pts): # call pyhull library output = pyhull.qconvex("Qt FA", pts) # parse output volume = -999.0 facetArea = -999.0 cnt1 = 0 cnt2 = 0 for line in output: if "facet area" in line: array = line.split(":") facetArea = float(array[1]) cnt1 += 1 if "volume" in line: array = line.split(":") volume = float(array[1]) cnt2 += 1 assert cnt1 == 1, "ERROR: 'facet area' found %d times in pyhull output" % cnt1 assert cnt2 == 1, "ERROR: 'volume' found %d times in pyhull output" % cnt2 return volume, facetArea
def compute_hiperspaces(self): # La característica heurística al buscar conexiones entre # diferentes clusters hace que pueda fallar # por lo que redirigimos la salida para ser silenciosos # en esos casos if not len(self.points) > 0: logger.error('No points to compute hull!') raise Exception('No points to compute hull!') stderr_fd = sys.stderr.fileno() with open('/tmp/qhull-output.log', 'w') as f, stderr_redirected(f): points = list(self.points) logger.info('Searching for hull in dimension %s based on %s points', len(points[0]),len(points)) output = qconvex('n',points) if len(output) == 1: logger.debug('Could not get Hull. Joggle input?') try: dim, facets_nbr, facets = self.__parse_hs_output(output) except IncorrectOutput: logger.warning('Could not get hull') raise CannotGetHull() logger.info('Found hull in dimension %s of %s facets', dim,len(facets)) self.dim = dim self.facets = facets if self.verbose: print "Computed MCH with ",facets_nbr," halfspaces" print 'This are them:\n' for facet in self.facets:print facet return self.dim
def zonotope_incidence_graph_opposite(A): V, S = zonotope_vertices(A) V_aff = project_affine_subspace(V.T).T if DEBUG: print('V_aff') print(V_aff) verts = [list(V_aff[i]) for i in range(V_aff.shape[0])] ret = pyhull.qconvex('Fv', verts) M = build_vertex_facet_matrix(ret, verts).T n = A.shape[0] d = V_aff.shape[1] I = build_incidence_graph(M, d) # Assign sign vectors for topes. for i in range(M.shape[1]): vf_key = tuple(np.where(M[:, i])[0].astype(int)) f = I.rank(d - 1)[vf_key] f.pos = S[i] # Assign sign vectors for k faces. for k in range(d - 2, -1, -1): for u in I.rank(k).values(): # print(u._sv_key, k) pos = np.zeros((n, ), int) for v in u.superfaces: # print('v', v.pos) pos += v.pos pos = (pos / len(u.superfaces)).astype(int) u.pos = pos # print('u', u.pos) return I
def zonotope_projected_vertex(normals): # N: normals of the hyperplanes num_normals = normals.shape[0] dim = normals.shape[1] V = np.vstack((normals[0], -normals[0])) Sign = np.array([[1], [-1]]) for i in range(1, num_normals): normal = normals[i] V_ = np.vstack((V + normal, V - normal)) Sign_ = np.ones((2 * Sign.shape[0], Sign.shape[1] + 1), dtype=int) Sign_[:, 0:Sign.shape[1]] = np.vstack((Sign, Sign)) Sign_[Sign.shape[0]:, -1] = -1 # take the convex hull of V_ orth = sp.linalg.orth((V_ - np.mean(V_, axis=0)).T) if orth.shape[1] != V.shape[1]: Vr = np.dot((V_ - np.mean(V_, axis=0)), orth) else: Vr = V_ - V_[1, :] vertices = [list(Vr[i]) for i in range(Vr.shape[0])] info['n'].append(len(vertices)) info['d'].append(len(vertices[0])) t_start = time() ret = pyhull.qconvex('Fv', vertices) info['time conv'].append(time() - t_start) #ind_vertices = [int(ret[j]) for j in range(1, len(ret))] ind_vertices = [] for i in range(1, len(ret)): ind_vertices = ind_vertices + [int(x) for x in ret[i].split(' ')][1:] ind_vertices = np.unique(ind_vertices) info['# d-1 faces'].append(len(ret) - 1) info['# 0 faces'].append(len(ind_vertices)) V = V_[ind_vertices] Sign = Sign_[ind_vertices] # # facets = np.zeros((int(ret[0]),len([int(x) for x in ret[1].split(' ')][1:])),dtype=int) # for i in range(1, len(ret)): # facets[i-1] = [int(x) for x in ret[i].split(' ')][1:] # ret_facets = np.array(facets) # # for i in range(len(ind_vertices)): # ret_facets[ret_facets == ind_vertices[i]] = i return V, Sign, info #, ret_facets
def main(): with open('res.txt', 'r') as rfile: lines = rfile.readlines() labels = np.array([x.split()[-1] for x in lines[1:]]) data = np.array([[float(x) for x in y.split()[:-1]] for y in lines[1:]]) data2 = data[:, :2] idx = [[int(x) for x in y.split()] for y in pyhull.qconvex('s i', data2)[1:]] coords = [[float(x) for x in y.split()] for y in pyhull.qconvex('s p', data2)[2:]] np_idx = np.array(idx) np_coords = np.array(coords) # print(idx) # print(coords) zero = np_coords[np_coords[:, 0] == 0][0][1] one = np_coords[np_coords[:, 0] == 1][0][1] zero_zero = np.copy(np_coords) zero_zero[:, 1] = np_coords[:, 1] - zero * (1 - np_coords[:, 0]) - one * np_coords[:, 0] bottom = np_coords[zero_zero[:, 1] <= 0] zero_zero = zero_zero[zero_zero[:, 1] <= 0] s_bottom = np.array(sorted(bottom, key=lambda x:x[0])) f = interpolate.interp1d(s_bottom[:, 0], s_bottom[:, 1]) # test plot # x = np.linspace(0, 1, 100) # pylab.plot(x, f(x)) # pylab.show() from_cvxhll = np.copy(data2) from_cvxhll[:, 1] = data2[:, 1] - f(data2[:, 0]) print(sum(from_cvxhll[:, 1] < 0.001)) low_e = data[from_cvxhll[:, 1] < 0.001] pylab.plot(low_e[:, 0], low_e[:, 1], 'o') pylab.plot(data[:, 0], data[:, 1], '*') # pylab.show() dir_list = labels[from_cvxhll[:, 1] < 0.001] for dirc in dir_list: print(dirc)
def construct_convex_hull_from_coords(coords: np.ndarray) -> Polyhedron: """Construct a polyhedron as a convex hull from a coordinate matrix. :param coords: An array of coordinates. :returns: A polyhedron whose facets are the non-simplicial facets of the convex hull of the vertices defined by `coords`. """ dim = coords.shape[1] assert dim <= 3, 'We cannot visualise anything with more than three\ dimensions.' vertices = [] for i in range(coords.shape[0]): if dim == 2: vertices.append(Point(np.array([coords[i, 0], coords[i, 1], 0]))) else: vertices.append(Point(coords[i, :])) if dim == 3: hull = qconvex("i", coords) n_facets = int(hull[0]) facets = [] for facet_vertices_str in hull[1:]: facet_vertices_idx = [ int(x) for x in facet_vertices_str.split(' ') ] facet_vertices = [vertices[i] for i in facet_vertices_idx] facet = Facet([Contour.from_vertices(facet_vertices)]) facets.append(facet) polyhedron = Polyhedron(facets) elif dim == 2: hull = qconvex("Fx", coords) n_hull_vertices = int(hull[0]) hull_vertices = [] for vertex_str in hull[1:]: vertex_idx = int(vertex_str) hull_vertices.append(vertices[vertex_idx]) contour = Contour.from_vertices(hull_vertices) polyhedron = Polyhedron([Facet([contour])]) return polyhedron
def zonotope_minkowski_sum(a, V, S): """Compute the Minkowski sum V ⊕ [a,-a]. Arguments: a {1xd vector} -- End-point of line segment [a,-a] V {nxd matrix} -- Zonotope vertices S {nxn matrix} -- Zonotope sign vectors Returns: [matrix, matrix] -- Updated zonotope vertices and sign vectors. """ a = np.reshape(a, (1, -1)) V_sum = np.vstack((V + a, V - a)) if DEBUG: print('V_sum') print(V_sum) S_sum = np.ones((2 * S.shape[0], S.shape[1] + 1), dtype=int) S_sum[:, 0:S.shape[1]] = np.vstack((S, S)) S_sum[S.shape[0]:, -1] = -1 if DEBUG: print('S_sum') print(S_sum) V_aff = project_affine_subspace(V_sum.T).T if DEBUG: print('V_aff') print(V_aff) vertices = [list(V_aff[i]) for i in range(V_aff.shape[0])] ret = pyhull.qconvex('Fv', vertices) idx = [] for i in range(1, len(ret)): idx = idx + [int(x) for x in ret[i].split(' ')][1:] idx = np.unique(idx) if DEBUG: print('idx') print(idx) V = V_sum[idx] S = S_sum[idx] return V, S
def get_lines_voronoi(data): from pyhull import qconvex output = qconvex("o", data) nb_points = int(output[1].split(" ")[0]) list_lines = [] list_points = [] for i in range(2, 2 + nb_points): list_points.append([float(c) for c in output[i].strip().split()]) facets = [] for i in range(2 + nb_points, len(output)): if output[i] != '': tmp = output[i].strip().split(" ") facets.append([int(tmp[j]) for j in range(1, len(tmp))]) for i in range(len(facets)): for line in itertools.combinations(facets[i], 2): for j in range(len(facets)): if i != j and line[0] in facets[j] and line[1] in facets[j]: #check if the two facets i and j are not coplanar vector1 = np.array(list_points[facets[j][0]])\ - np.array(list_points[facets[j][1]]) vector2 = np.array(list_points[facets[j][0]])\ - np.array(list_points[facets[j][2]]) n1 = np.cross(vector1, vector2) vector1 = np.array(list_points[facets[i][0]])\ - np.array(list_points[facets[i][1]]) vector2 = np.array(list_points[facets[i][0]])\ - np.array(list_points[facets[i][2]]) n2 = np.cross(vector1, vector2) dot = math.fabs( np.dot(n1, n2) / (np.linalg.norm(n1) * np.linalg.norm(n2))) if 1.05 > dot > 0.95: continue list_lines.append({ 'start': list_points[line[0]], 'end': list_points[line[1]] }) break return list_lines
def construct_convex_hull(vertices: Sequence[Point]) -> Polyhedron: """Construct a polyhedron as a convex hull from a list of vertices. :param vertices: A list of all vertices to be analysed. :returns: A polyhedron whose facets are the non-simplicial facets of the convex hull of `vertices`. """ coords = np.zeros((len(vertices), 3)) for i, vertex in enumerate(vertices): coords[i, :] = vertex.coordinates hull = qconvex("i", coords) n_facets = int(hull[0]) facets = [] for facet_vertices_str in hull[1:]: facet_vertices_idx = [int(x) for x in facet_vertices_str.split(' ')] facet_vertices = [vertices[i] for i in facet_vertices_idx] facet = Facet([Contour.from_vertices(facet_vertices)]) facets.append(facet) polyhedron = Polyhedron(facets) return polyhedron
def __init__(self, points, joggle=False): """ Args: points: All the points as a sequence of sequences. e.g., [[-0.5, -0.5], [-0.5, 0.5], [0.5, -0.5], [0.5, 0.5]] joggle: Use qhull option to joggle inputs until simplical result is obtained instead of merging facets. """ self.points = points dim = map(len, self.points) if max(dim) != min(dim): raise ValueError("Input points must all have the same dimension!") self.dim = dim[0] if joggle: options = "i QJ" else: options = "i Qt" output = qconvex(options, points) output.pop(0) self.vertices = [map(int, row.strip().split()) for row in output]
def __init__(self, points, joggle=False): """ Initializes a ConvexHull from points. Args: points ([[float]]): All the points as a sequence of sequences. e.g., [[-0.5, -0.5], [-0.5, 0.5], [0.5, -0.5], [0.5, 0.5]] joggle (bool): Use qhull option to joggle inputs until simplical result is obtained instead of merging facets. """ self.points = points dim = [len(i) for i in self.points] if max(dim) != min(dim): raise ValueError("Input points must all have the same dimension!") self.dim = dim[0] if joggle: options = "i QJ" else: options = "i Qt" output = qconvex(options, points) output.pop(0) self.vertices = [[int(i) for i in row.strip().split()] for row in output]
def vertex2lattice(V): # orth = sp.linalg.orth((V - np.mean(V, 0)).T) # dim_V = orth.shape[1] #print(V) V_aff = proj_affine(V.T).T #print(V_aff) dim_V = V_aff.shape[1] n_vert = V.shape[0] if n_vert == 2 or n_vert == 1 or dim_V == 1: M = np.ones((n_vert, 1), int) L = FaceLattice(M, dim_V) return L # project V into affine space # if dim_V != V.shape[1]: # V = np.dot((V - np.mean(V,0)), orth) # vertices = [list(V[i]) for i in range(n_vert)] vertices = [list(V_aff[i]) for i in range(n_vert)] ret = pyhull.qconvex('Fv', vertices) # get the convex hull of V # select faces with desired modes # Build facet-vertex incidence matrix. n_facets = int(ret[0]) M = np.zeros((n_vert, n_facets), int) for i in range(1, len(ret)): vert_set = [int(x) for x in ret[i].split(' ')][1:] for v in vert_set: M[v, i - 1] = 1 # Build face lattice. L = FaceLattice(M, dim_V) return L
def count_surface(sites): """ 多面体を構成する面の数を return する """ out = pyhull.qconvex('s i', sites) # voro = pyhull.qvoronoi('s o', sites) return len(out) - 1
def computeConvexHullVolume(points): outputStr = qconvex("FA", points) volumeSize = outputStr[-2].split()[3] print "ConvexHullSize:",volumeSize return volumeSize
def zonotope_vertex(normals): # solve info info = dict() info['iter'] = [] info['n'] = [] info['d'] = [] info['time conv'] = [] info['# 0 faces'] = [] info['# d-1 faces'] = [] # normals_proj = proj_affine(normals.T).T # normals_u, idu = unique_row(normals_proj) # normals = normals_u # N: normals of the hyperplanes num_normals = normals.shape[0] dim = normals.shape[1] V = np.vstack((normals[0], -normals[0])) Sign = np.array([[1], [-1]]) for i in range(1, num_normals): info['iter'].append(i) normal = normals[i] V_ = np.vstack((V + normal, V - normal)) Sign_ = np.ones((2 * Sign.shape[0], Sign.shape[1] + 1), dtype=int) Sign_[:, 0:Sign.shape[1]] = np.vstack((Sign, Sign)) Sign_[Sign.shape[0]:, -1] = -1 # take the convex hull of V_ # orth = sp.linalg.orth((V_ - np.mean(V_,axis=0)).T) Vr = proj_affine(V_.T).T #print(Vr) # if orth.shape[1] != V.shape[1]: # Vr = np.dot((V_ - np.mean(V_,axis=0)), orth) # else: # Vr = V_ - np.mean(V_,axis=0) if Vr.shape[1] <= 1: V = V_[[np.argmax(Vr), np.argmin(Vr)]] Sign = Sign_[[np.argmax(Vr), np.argmin(Vr)]] continue vertices = [list(Vr[i]) for i in range(Vr.shape[0])] ret = pyhull.qconvex('Fv', vertices) if len(ret) - 1 == 0: return [], [] #ind_vertices = [int(ret[j]) for j in range(1, len(ret))] ind_vertices = [] for i in range(1, len(ret)): ind_vertices = ind_vertices + [int(x) for x in ret[i].split(' ')][1:] ind_vertices = np.unique(ind_vertices) #print(ret) V = V_[ind_vertices] Sign = Sign_[ind_vertices] # # facets = np.zeros((int(ret[0]),len([int(x) for x in ret[1].split(' ')][1:])),dtype=int) # for i in range(1, len(ret)): # facets[i-1] = [int(x) for x in ret[i].split(' ')][1:] # ret_facets = np.array(facets) # # for i in range(len(ind_vertices)): # ret_facets[ret_facets == ind_vertices[i]] = i #Sign = Sign[:,idu] return V, Sign #, ret_facets
def prob_qhull(samples, data, rho_D_M, d_distr_samples, lam_domain, d_Tree=None): r""" Calculates :math:`P_{\Lambda}(\mathcal{V}_{\lambda_{emulate}})`, the probability assoicated with a set of voronoi cells defined by ``num_l_emulate`` iid samples :math:`(\lambda_{emulate})`. This method is only intended when ``lam_domain`` is a generalized rectangle. :param samples: The samples in parameter space for which the model was run. :type samples: :class:`~numpy.ndarray` of shape (num_samples, ndim) :param data: The data from running the model given the samples. :type data: :class:`~numpy.ndarray` of size (num_samples, mdim) :param rho_D_M: The simple function approximation of rho_D :type rho_D_M: :class:`~numpy.ndarray` of shape (M,mdim) :param d_distr_samples: The samples in the data space that define a parition of D to for the simple function approximation :type d_distr_samples: :class:`~numpy.ndarray` of shape (M,mdim) :param d_Tree: :class:`~scipy.spatial.KDTree` for d_distr_samples :param lam_domain: The domain for each parameter for the model. :type lam_domain: :class:`~numpy.ndarray` of shape (ndim, 2) :returns: (P, io_ptr, lam_vol) """ import pyhull if len(d_distr_samples.shape) == 1: d_distr_samples = np.expand_dims(d_distr_samples, axis=1) if d_Tree == None: d_Tree = spatial.KDTree(d_distr_samples) # Determine which inputs go to which M bins using the QoI #io_ptr = dsearchn(d_distr_samples, data); io_ptr = d_Tree.query(data) # Calcuate the bounding region for the parameters lam_bound = np.copy(samples) lam_width = lam_domain[:, 1] - lam_domain[:, 0] nbins = d_distr_samples.shape[1] # Add fake samples outside of lam_domain to close Voronoi tesselations. pts_per_edge = nbins sides = np.zeros((2, pts_per_edge)) for i in range(lam_domain.shape[0]): sides[i, :] = np.linspace(lam_domain[i, 0], lam_domain[i, 1], pts_per_edge) # add midpoints for i in range(lam_domain.shape[0]): new_pt = sides new_pt[i, :] = np.repeat(lam_domain[i, 0] - lam_width[i]/pts_per_edge, pts_per_edge, 0).transpose() lam_bound = np.vstack((lam_bound, new_pt)) new_pt = sides new_pt[i, :] = np.repeat(lam_domain[i, 1] - lam_width[i]/pts_per_edge, pts_per_edge, 0).transpose() lam_bound = np.vstack((lam_bound, new_pt)) # add corners corners = np.zeros((2**lam_domain.shape[0], lam_domain.shape[0])) for i in range(lam_domain.shape[0]): corners[i, :] = lam_domain[i, np.repeat(np.hstack((np.ones((1, 2**(i-1))), 2*np.ones((1, 2**(i - 1))))), 2**(lam_domain.shape[0]-i), 0).transpose()] corners[i, :] += lam_width[i]*np.repeat(np.hstack((np.ones((1, 2**(i-1))), -np.ones((1, 2**(i - 1))))), 2**(lam_domain.shape[0]-i)/pts_per_edge, 0).transpose() lam_bound = np.vstack((lam_bound, corners)) # Calculate the Voronoi diagram for samples. Calculate the volumes of # the convex hulls of the corresponding Voronoi regions. lam_vol = np.zeros((samples.shape[-1],)) for i in range((samples.shape[0])): vornoi = spatial.Voronoi(lam_bound) lam_vol[i] = float(pyhull.qconvex('Qt FA', vornoi.vertices).split()[-1]) # Calculate probabilities. P = np.zeros((samples.shape[0],)) for i in range(rho_D_M.shape[0]): Itemp = np.equal(io_ptr, i) P[Itemp] = rho_D_M[i]*lam_vol[Itemp]/np.sum(lam_vol[Itemp]) P = P/np.sum[P] return (P, lam_vol, io_ptr)
def enumerate_contact_separating_3d(A, b): # Create solve info. info = dict() # Create halfspace inequalities, Ax - b <= 0. # A, b = build_normal_velocity_constraints(system.collider.manifolds) # b = np.zeros(b.shape) if DEBUG: print('A') print(A) print('b') print(b) n_pts = A.shape[0] info['n'] = n_pts # Get interior point using linear programming. t_lp = time() int_pt = int_pt_cone(A) info['time lp'] = time() - t_lp if DEBUG: print('int_pt2') print(int_pt, '\n', A @ int_pt) # Filter contact points which are always in contact. mask = np.zeros(n_pts, dtype=bool) c = np.where(np.abs(A @ int_pt) < 1e-6)[0] # always contacting. mask[c] = 1 A_c = A[mask, :] b_c = b[mask, :] A = A[~mask, :] b = b[~mask, :] if DEBUG: print(c) print(mask) # Project into null space of contacting points. # [A'; A_c]x ≤ 0, A_c⋅x = 0 ⇒ x ∈ NULL(A_c) # let NULL(A_c) = [x0, ... , xc] # A'⋅NULL(A_c)x' ≤ 0 if np.sum(mask) > 0: N = null(A_c, np.finfo(np.float32).eps) A = A @ N int_pt = np.linalg.lstsq(N, int_pt, None)[0] if DEBUG: print('Null A_c') print(N) print('new int pt') print(int_pt) print(A @ int_pt) # Compute dual points. b_off = b - np.dot(A, int_pt) dual = A / b_off if DEBUG: print('b off') print(b_off) print('dual') print(dual) # Handle degenerate cases when d = 0 or 1. if np.sum(mask) == n_pts: cs_modes = [np.array(['c'] * n_pts)] lattice = FaceLattice() lattice.L = [[Face(range(n_pts), 0)]] lattice.L[0][0].m = cs_modes[0] return cs_modes, lattice, info if dual.shape[1] == 1: lattice = FaceLattice(M=np.ones((1, 1), int), d=1) dual_map = [list(np.where(~mask)[0])] cs_modes = lattice.csmodes(mask, dual_map) lattice.L = lattice.L[1:3] return cs_modes[1:3], lattice, info # Project dual points into affine space. dual = proj_affine(dual.T).T if DEBUG: print('proj dual') print(dual) info['d'] = dual.shape[1] # Filter duplicate points. idx = np.lexsort(np.rot90(dual)) dual_map = [] dual_unique = [] i = 0 while i < len(idx): if i == 0: dual_unique.append(dual[idx[i], :]) dual_map.append([idx[i]]) else: curr = dual[idx[i], :] last = dual_unique[-1] if np.linalg.norm(last - curr) < 1e-6: dual_map[-1].append(idx[i]) else: dual_unique.append(dual[idx[i], :]) dual_map.append([idx[i]]) i += 1 if DEBUG: print('dual map') print(dual_map) print('dual unique') print(dual_unique) # Handle various cases. dual = [list(dual_unique[i]) for i in range(len(dual_unique))] if len(dual_unique) == 1: d = 0 M = np.array([[]]) elif len(dual_unique[0]) == 1: d = 1 M = np.zeros((len(dual), 2), int) i_min = np.argmin(np.array(dual).flatten()) i_max = np.argmax(np.array(dual).flatten()) M[i_min, 0] = 1 M[i_max, 1] = 1 else: d = len(dual[0]) # Compute dual convex hull. t_start = time() ret = pyhull.qconvex('Fv', dual) info['time conv'] = time() - t_start if DEBUG: print(np.array(ret)) # Build facet-vertex incidence matrix. n_facets = int(ret[0]) M = np.zeros((len(dual), n_facets), int) for i in range(1, len(ret)): vert_set = [int(x) for x in ret[i].split(' ')][1:] for v in vert_set: M[v, i - 1] = 1 if DEBUG: print('dual') print(np.array(dual)) if DEBUG: print('M') print(M) # Build face lattice. t_start = time() lattice = FaceLattice(M, d) info['time lattice'] = time() - t_start # Build mode strings. cs_modes = lattice.csmodes(mask, dual_map) if DEBUG: print(cs_modes) info['# 0 faces'] = lattice.num_k_faces(0) info['# d-1 faces'] = lattice.num_k_faces(info['d'] - 1) info['# faces'] = lattice.num_faces() # Return mode strings. return cs_modes, lattice, info