Visual Studio Error 2784 : could not deduce template argument for GMP from FLINT - gmp

I have a problem running the source code of "homomorphic Simon encryption using YASHE and FV leveled homomorphic cryptosystems" (https://github.com/tlepoint/homomorphic-simon) in Visual Studio 2012.
I'm using FLINT 2.5.2, MPIR 2.7.2, MPFR 1.3.1 and getting numerous errors as follows :
#include "stdafx.h"
#include "FVKey.h"
#include "Sampler.h"
#include <iostream>
#include "arith.h"
#include "timing.h"
#include <string>
/* Static values */
fmpzxx W((fmpzxx(1) << WORDLENGTH)); //error C2678
fmpzxx MASKING((fmpzxx(1) << WORDLENGTH)-fmpzxx(1)); //error C2678
/* Print Key */
std::ostream& operator<<(std::ostream& os, const FVKey& k) {
os << "<FVKey with ell=" << k.ell << " num_slots=" << k.get_num_slots() << " q=" << k.q
<< " t=" << k.t << " sigma_key=" << k.sigmakey << " sigma_err=" << k.sigmaerr
<< ">";
return os;
}
/* Small useful functions */
bool isPowerOfTwo(int n)
{
return (n) && !(n & (n - 1)); //this checks if the integer n is a power of two or not
}
void binaryGen(fmpz_mod_polyxx& f, unsigned degree)
{
for (unsigned i=0; i<=degree; i++)
f.set_coeff(i, fmpzxx((rand()%3)-1));
}
fmpz_mod_polyxx FVKey::BitVectorToPoly(BitVector& m)
{
assert(m.l() == num_slots);
if (!batching || num_slots == 1)
{
fmpz_mod_polyxx pf(q);
for (unsigned i=0; i<m.l(); i++)
pf.set_coeff(i, m[i]);
return pf;
}
else
{
fmpz_mod_polyxx pf(t);
fmpz_mod_polyxx mess(t);
mess.set_coeff(0, m[0]);
pf = mess;
for (unsigned i=1; i<num_slots; i++)
{
mess.set_coeff(0, m[i]);
pf = CRT(pf, mess, i-1);
}
fmpz_mod_polyxx result(q);
result = pf.to<fmpz_polyxx>();
return result;
}
}
unsigned noise_from_poly(const fmpz_mod_polyxx& cval, const fmpzxx &q, unsigned ell)
{
unsigned bitnoise = 0;
fmpzxx coeff;
for (unsigned i=0; i<ell; i++)
{
coeff = (cval.get_coeff(i).to<fmpzxx>()); //error C2893 ,C2228,C2059
if (2*coeff > q) //error C2893, error C2784
coeff = coeff - q; //error C2893, error C2784
if (coeff.sizeinbase(2)>bitnoise)
bitnoise = coeff.sizeinbase(2);
}
return bitnoise;
}
/* Constructor */
FVKey::FVKey(const struct FVParams& params, bool batch)
{
// Initializations
n = params.n;
sigmakey = params.sigmakey;
sigmaerr = params.sigmaerr;
q = params.q;
t = params.t;
logwq = q.sizeinbase(2)/WORDLENGTH+1;
qdivt = q/t; //error C2893, error C2784
qdiv2t = q/(2*t); //error C2784
// Define polynomial modulus
arith_cyclotomic_polynomial(poly._data().inner, n);
phi = new fmpz_mod_polyxx(q);
*phi = poly;
ell = phi->degree();
// Factorize the modulus if batching is set
batching = batch;
num_slots = 1;
if (batching)
{
std::cout << "Factorize the cyclotomic polynomial modulo " << t << std::endl;
fmpz_mod_polyxx phimodt(t);
phimodt = poly;
timing T;
T.start();
factors = new fmpz_mod_poly_factorxx(factor_cantor_zassenhaus(phimodt));
T.stop("Factorize");
unsigned degreeFactors = 0;
for (unsigned i=0; i<factors->size(); i++)
{
degreeFactors += factors->p(i).degree();
}
if (degreeFactors == phimodt.degree() && factors->size()>1)
{
std::cout << "Batching possible on " << factors->size() << " slots" << std::endl;
num_slots = factors->size();
invfactors.resize(num_slots-1, fmpz_mod_polyxx(t));
fmpz_mod_polyxx num(t);
num.set_coeff(0, 1);
for (unsigned i=0; i<num_slots-1; i++)
{
num = num*factors->p(i);
invfactors[i] = num.invmod(factors->p(i+1));
}
}
else
{
std::cout << "Batching impossible" << std::endl;
}
}
// Creating sk/pk
std::cerr << "Creating sk/pk" << std::endl;
a = new fmpz_mod_polyxx(q);
s = new fmpz_mod_polyxx(q);
b = new fmpz_mod_polyxx(q);
for (unsigned i=0; i<ell; i++)
{
fmpzxx coeff = fmpzxx(random.getRandomLong());
for (unsigned j=0; j<q.sizeinbase(2)/64; j++)
coeff = (coeff<<64)+fmpzxx(random.getRandomLong());
a->set_coeff(i, coeff);
}
samplerkey = new Sampler(sigmakey*0.4, 1., &random); // 1/sqrt(2*pi) ~ 0.4
if (sigmakey == 1) binaryGen(*s, ell-1);
else
{
for (unsigned i=0; i<ell; i++)
{
long value = samplerkey->SamplerGaussian();
if (value>=0) s->set_coeff(i, fmpzxx(value));
else s->set_coeff(i, q-fmpzxx(-value));
}
}
samplererr = new Sampler(sigmaerr*0.4, 1., &random); // 1/sqrt(2*pi) ~ 0.4
fmpz_mod_polyxx e(q);
if (sigmaerr == 1) binaryGen(e, ell-1);
else
{
for (unsigned i=0; i<ell; i++)
{
long value = samplererr->SamplerGaussian();
if (value>=0) e.set_coeff(i, fmpzxx(value));
else e.set_coeff(i, q-fmpzxx(-value));
}
}
*b = (-((*a)*(*s)%(*phi)))+e;
// Create evaluation key
gamma.resize(2);
gamma[0].resize(logwq, fmpz_mod_polyxx(q));
for (unsigned i=0; i<logwq; i++)
{
for (unsigned j=0; j<ell; j++)
{
fmpzxx coeff = fmpzxx(random.getRandomLong());
for (unsigned k=0; k<q.sizeinbase(2)/64; k++)
coeff = (coeff<<64)+fmpzxx(random.getRandomLong());
gamma[0][i].set_coeff(j, coeff);
}
}
gamma[1].resize(logwq, fmpz_mod_polyxx(q));
for (unsigned i=0; i<logwq; i++)
{
gamma[1][i] = (*s)*(*s);
for (unsigned j=0; j<i; j++)
gamma[1][i] = gamma[1][i]*W;
fmpz_mod_polyxx e2(q);
if (sigmaerr == 1) binaryGen(e2, ell-1);
else
{
for (unsigned i=0; i<ell; i++)
{
long value = samplererr->SamplerGaussian();
if (value>=0) e2.set_coeff(i, fmpzxx(value));
else e2.set_coeff(i, q-fmpzxx(-value));
}
}
gamma[1][i] += (-(gamma[0][i]*(*s)%(*phi)))+e2;
}
}
Error C2784:
'__gmp_expr,mpir_ui,__gmp_binary_multiplies>>
operator *(const __gmp_expr &,unsigned __int64)' : could not
deduce template argument for 'const __gmp_expr &' from
'int' fvkey.cpp 115 Error C2784:
'__gmp_expr,__gmp_binary_multiplies>>
operator *(unsigned short,const __gmp_expr &)' : could not deduce
template argument for 'const __gmp_expr &' from 'flint::fmpzxx'
Error C2784:
'__gmp_expr,__gmp_binary_minus>> operator -(unsigned short,const __gmp_expr &)' : could not deduce
template argument for 'const __gmp_expr &' from 'const
flint::fmpzxx' fvkey.cpp 116
Error C2784:
'__gmp_expr,__gmp_binary_divides>>
operator /(unsigned short,const __gmp_expr &)' : could not deduce
template argument for 'const __gmp_expr &' from
'flint::fmpzxx' fvkey.cpp 135 Error C2784:
'__gmp_expr,__gmp_binary_multiplies>>
operator *(signed char,const __gmp_expr &)' : could not deduce
template argument for 'const __gmp_expr &' from 'flint::fmpzxx'
fvkey.cpp 115
Error C2784: '__gmp_expr,__gmp_binary_minus>> operator -(long
double,const __gmp_expr &)' : could not deduce template argument
for 'const __gmp_expr &' from 'const flint::fmpzxx'
'flint::fmpzxx' fvkey.cpp 116
Error C2784:
'__gmp_expr,mpir_ui,__gmp_binary_multiplies>>
operator *(const __gmp_expr &,unsigned int)' : could not deduce
template argument for 'const __gmp_expr &' from
'int' 'flint::fmpzxx' fvkey.cpp 115
Error C2678: binary '<<' : no operator found which takes a left-hand
operand of type 'flint::fmpzxx_expression' (or there
is no acceptable conversion) fvkey.cpp 50
I've tried to solve it couple of weeks but still unsuccessfully. Whether it is caused by the "fmpz-conversions.h" from FLINT?
Please help me to figure out what I've done incorrectly. I've uploaded my visual project to http://1drv.ms/1LFpCI4.

Related

Expansion of periodic mesh

I have send this trough the mailing list but it seems not to be fully working at the moment so I am posting it here instead. The issue I am having is that I am trying to expand a periodic mesh and have it returned in a new c3t3 structure instead of having to save a .mesh file and load it afterwards. For this I have tried modifying the File_medit.h found in the Periodic_3_mesh_3/IO folder but am having a few issues. First of all, the tetrahedrals seem to not be properly added when I call the build_triangulation function although the finite_cell vector has all collected values in it. I am having a similar issue with the border_facets, although in this case I am also not sure what data I am supposed to place in surface_patch_id and if perhaps this is causing the issues. I have included the code I am using bellow. Any help is appreciated.
Regards, Kim
/* ==========================================================================
* Based on CGAL's File_medit.h. See CGAL Periodic_3_mesh_3/IO.
* ==========================================================================*/
#ifndef CGAL_PERIODIC_REPLICATOR_H
#define CGAL_PERIODIC_REPLICATOR_H
#include <CGAL/license/Periodic_3_mesh_3.h>
#include <CGAL/Mesh_3/io_signature.h>
#include <CGAL/Mesh_3/tet_soup_to_c3t3.h>
//
#include <CGAL/array.h>
#include <CGAL/assertions.h>
#include <CGAL/IO/File_medit.h>
#include <boost/unordered_map.hpp>
#include <algorithm>
#include <fstream>
#include <iostream>
#include <cstring>
#include <sstream>
#include <cstring>
#include <map>
namespace CGAL {
namespace periodic_replicator {
/**
* \brief expands a periodic mesh to the c3t3 variable
* \param c3t3_periodic the mesh
* \param occurrence_count the number of copies that are printed
* \param distinguish_copies if set to `true`, each copy is assigned a unique color.
* Otherwise, all domains are drawn with subdomain index-based colors.
* \param rebind if set to `true`, labels of cells are rebinded into [1..nb_of_labels]
* \param c3t3 the output mesh
*/
template <class C3T3_Periodic, class C3T3, bool rebind, bool no_patch> ////template <class C3T3_Periodic>
void replicate_periodic_mesh(const C3T3_Periodic& c3t3_periodic,
int occurrence_count[3],
const bool distinguish_copies,
C3T3& c3t3)
{
#ifdef CGAL_MESH_3_IO_VERBOSE
std::cerr << "Output to medit:\n";
#endif
CGAL_precondition(c3t3_periodic.triangulation().is_1_cover());
typedef CGAL::Mesh_3::Medit_pmap_generator<C3T3_Periodic, rebind, no_patch> Generator;
typedef typename Generator::Cell_pmap Cell_pmap;
typedef typename Generator::Facet_pmap Facet_pmap;
typedef typename Generator::Facet_pmap_twice Facet_pmap_twice;
typedef typename Generator::Vertex_pmap Vertex_pmap;
//Generator().print_twice();
Cell_pmap cell_pmap(c3t3_periodic);
Facet_pmap facet_pmap(c3t3_periodic, cell_pmap);
Facet_pmap_twice facet_pmap_twice(c3t3_periodic, cell_pmap);
Vertex_pmap vertex_pmap(c3t3_periodic, cell_pmap, facet_pmap);
// const Facet_index_property_map_twice& facet_twice_pmap = Facet_index_property_map_twice(),
const bool print_each_facet_twice = false;//Generator().print_twice();
CGAL_precondition(occurrence_count[0] >= 1 && occurrence_count[1] >= 1 && occurrence_count[2] >= 1);
// Periodic typedef
typedef typename C3T3_Periodic::Triangulation Triangulation_periodic;
typedef Triangulation_periodic Tr_periodic;
typedef typename Tr_periodic::Bare_point Bare_point;
typedef typename Tr_periodic::Weighted_point Weighted_point;
typedef typename C3T3_Periodic::Vertex_handle Vertex_handle;
typedef typename C3T3_Periodic::Cell_handle Cell_handle;
typedef typename Tr_periodic::Vertex_iterator Vertex_iterator;
typedef typename C3T3_Periodic::Facet_iterator Facet_iterator;
typedef typename C3T3_Periodic::Cell_iterator Cell_iterator;
typedef typename Tr_periodic::Offset Offset;
const Triangulation_periodic& tr_periodic = c3t3_periodic.triangulation();
// Non-periodic typedef
typedef typename C3T3::Triangulation Triangulation;
typedef Triangulation Tr;
typedef typename Tr::Point Point_3;
typedef std::array<int, 3> Facet; // 3 = id
typedef std::array<int, 5> Tet_with_ref; // first 4 = id, fifth = reference
//
std::vector<Point_3> points;
//std::map<Facet, typename Tr::Cell::Surface_patch_index> border_facets_;
std::map<Facet, typename C3T3::Surface_patch_index> border_facets;
std::vector<Tet_with_ref> finite_cells;
//
int number_of_vertices = static_cast<int>(tr_periodic.number_of_vertices());
int number_of_facets = static_cast<int>(c3t3_periodic.number_of_facets());
int number_of_cells = static_cast<int>(c3t3_periodic.number_of_cells());
// number of reproductions over the different axes
int Ox_rn = ceil(occurrence_count[0]);
int Oy_rn = ceil(occurrence_count[1]);
int Oz_rn = ceil(occurrence_count[2]);
int occ_mult = Ox_rn * Oy_rn * Oz_rn;
#ifdef CGAL_PERIODIC_3_MESH_3_VERBOSE
std::cerr << "Expanding periodic mesh... " << std::endl;
std::cerr << "occurrences over each axis: "
<< Ox_rn << " " << Oy_rn << " " << Oz_rn << std::endl;
std::cerr << number_of_vertices << " vertices" << std::endl;
std::cerr << number_of_facets << " facets" << std::endl;
std::cerr << number_of_cells << " cells" << std::endl;
#endif
std::ofstream os("output_control.mesh");
os << std::setprecision(17);
// Vertices
int medit_number_of_vertices = (Ox_rn + 1) * (Oy_rn + 1) * (Oz_rn + 1) * number_of_vertices;
os << "MeshVersionFormatted 1\n"
<< "Dimension 3\n"
<< "Vertices\n" << medit_number_of_vertices << std::endl;
// Build the set of points that is needed to draw all the elements.
// On each axis, we repeat n+1 times the point, where 'n' is the number of
// instances of the mesh that will be printed over that axis. This is because
// a cell 'c' might have point(c,i) that is equal to v with an offset 2
boost::unordered_map<Vertex_handle, int> V;
int inum = 1; // '1' because medit ids start at 1
for(int i=0; i<=Oz_rn; ++i) {
for(int j=0; j<=Oy_rn; ++j) {
for(int k=0; k<=Ox_rn; ++k) {
for(Vertex_iterator vit = tr_periodic.vertices_begin(); vit != tr_periodic.vertices_end(); ++vit) {
if(i == 0 && j == 0 && k == 0)
V[vit] = inum++;
const Offset off(k, j, i);
const Weighted_point& p = tr_periodic.point(vit);
const Bare_point bp = tr_periodic.construct_point(p, off);
int id;
if(i >= 1 || j >= 1 || k >= 1)
id = 7;
else
id = tr_periodic.off_to_int(off);
os << CGAL::to_double(bp.x()) << ' '
<< CGAL::to_double(bp.y()) << ' '
<< CGAL::to_double(bp.z()) << ' ';
if(!distinguish_copies || occ_mult == 1)
os << get(vertex_pmap, vit) << '\n';
else
os << 32 * id + 1 << '\n';
points.push_back(Point_3(CGAL::to_double(bp.x()),
CGAL::to_double(bp.y()),
CGAL::to_double(bp.z())));
}
}
}
}
// Triangles
int medit_number_of_triangles = occ_mult * number_of_facets;
if(print_each_facet_twice)
medit_number_of_triangles *= 2;
os << "Triangles\n" << medit_number_of_triangles << std::endl;
for(int i=0; i<Oz_rn; ++i) {
for(int j=0; j<Oy_rn; ++j) {
for(int k=0; k<Ox_rn; ++k) {
const Offset off(k, j, i);
for(Facet_iterator fit = c3t3_periodic.facets_begin(); fit != c3t3_periodic.facets_end(); ++fit) {
typename Tr::Cell::Surface_patch_index surface_patch_id;
Facet facet;
for(int l=0; l<4; ++l) {
if(l == fit->second)
continue;
Cell_handle c = fit->first;
Vertex_handle v = c->vertex(l);
const Offset combined_off = tr_periodic.combine_offsets(
off, tr_periodic.int_to_off(c->offset(l)));
const int vector_offset = combined_off.x() +
combined_off.y() * (Ox_rn + 1) +
combined_off.z() * (Ox_rn + 1) * (Oy_rn + 1);
const int id = vector_offset * number_of_vertices + V[v];
CGAL_assertion(1 <= id && id <= medit_number_of_vertices);
os << id << " ";
//facet[l] = id;
int temp_ = id;
facet[l] = temp_;
}
// For multiple copies, color to distinguish copies rather than to distinguish subdomains
//int temptest;
if(!distinguish_copies || occ_mult == 1){
os << get(facet_pmap, *fit) << '\n';
} else {
os << 1 + k + 3*j + 9*i << '\n';
}
surface_patch_id.first = 0;
surface_patch_id.second = 1;
border_facets.insert(std::make_pair(facet, surface_patch_id));
// Print triangle again if needed
if(print_each_facet_twice) {
for(int l=0; l<4; ++l) {
if(l == fit->second)
continue;
Cell_handle c = fit->first;
Vertex_handle v = c->vertex(l);
const Offset combined_off = tr_periodic.combine_offsets(
off, tr_periodic.int_to_off(c->offset(l)));
const int vector_offset = combined_off.x() +
combined_off.y() * (Ox_rn + 1) +
combined_off.z() * (Ox_rn + 1) * (Oy_rn + 1);
const int id = vector_offset * number_of_vertices + V[v];
CGAL_assertion(1 <= id && id <= medit_number_of_vertices);
os << id << " ";
int temp_ = id;
facet[l] = temp_;
}
if(!distinguish_copies || occ_mult == 1)
os << get(facet_pmap_twice, *fit) << '\n';
else
os << 1 + k + 3*j + 9*i << '\n';
//surface_patch_id = ???;
//border_facets.insert(std::make_pair(facet, surface_patch_id));
}
}
}
}
}
// Tetrahedra
os << "Tetrahedra\n" << occ_mult * number_of_cells << std::endl;
for(int i=0; i<Oz_rn; ++i) {
for(int j=0; j<Oy_rn; ++j) {
for(int k=0; k<Ox_rn; ++k) {
const Offset off(k, j, i);
for(Cell_iterator cit = c3t3_periodic.cells_begin(); cit !=c3t3_periodic.cells_end(); ++cit) {
Tet_with_ref t;
for(int l=0; l<4; ++l) {
const Offset combined_off = tr_periodic.combine_offsets(
off, tr_periodic.int_to_off(cit->offset(l)));
const int vector_offset = combined_off.x() +
combined_off.y() * (Ox_rn + 1) +
combined_off.z() * (Ox_rn + 1) * (Oy_rn + 1);
const int id = vector_offset * number_of_vertices + V[cit->vertex(l)];
CGAL_assertion(1 <= id && id <= medit_number_of_vertices);
os << id << " ";
t[l] = id - 1;
}
// For multiple copies, color to distinguish copies rather than to distinguish subdomains
if(!distinguish_copies || occ_mult == 1) {
os << get(cell_pmap, cit) << '\n';
t[4] = get(cell_pmap, cit);
} else {
os << 1 + k + 3*j + 9*i << '\n';
t[4] = 1 + k + 3*j + 9*i;
}
finite_cells.push_back(t);
}
}
}
}
os << "End" << std::endl;
//
//std::vector<typename Tr::Vertex_handle> vertices(0);
std::vector<typename Tr::Vertex_handle> vertices(points.size() + 1);
bool is_well_built = build_triangulation<Tr, true>(c3t3.triangulation(), points, finite_cells, border_facets, vertices, true/*verbose*/, false/*replace_domain*/);
// Check
std::cout << points.size() << " points" << std::endl;
std::cout << border_facets.size() << " border facets" << std::endl;
std::cout << finite_cells.size() << " cells" << std::endl;
std::cout << c3t3.number_of_facets() << " border facets expanded c3t3" << std::endl;
std::cout << c3t3.number_of_cells() << " cells expanded c3t3" << std::endl;
}
#ifdef CGAL_MESH_3_IO_VERBOSE
std::cerr << "done.\n";
#endif
} // namespace periodic_replicator
} // namespace CGAL
#endif // CGAL_PERIODIC_REPLICATOR_H

What is the problem with generated SPIR-V code and how to verify it?

I have some generated SPIR-V code which I want to use with the vulkan API. But I get an
Exception thrown at 0x00007FFB68D933CB (nvoglv64.dll) in vulkanCompute.exe: 0xC0000005: Access violation reading location 0x0000000000000008. when trying to create the pipline with vkCreateComputePipelines.
The API calls should be fine, because the same code works with a shader compiled with glslangValidator. Therefore I assume that the generated SPIR-V code must be illformed somehow.
I've checked the SPIR-V code with the validator tool from khronos, using spirv-val --target-env vulkan1.1 mainV.spv which exited without error. Anyhow it is also known that this tool is still incomplete.
I've also tried to use the Radeon GPU Analyzer to compile my SPIR-V code, which is also available online at the shader playground and this tool throws the error Error: Error: internal error: Bil::BilInstructionConvert::Create(60) Code Not Tested! which is not really helpful, but encourages the assumption that the code is malformed.
The SPIR-V code is unfortunately to long to post it here, but it is in the link of the shader playground.
Does anyone know what the problem is with my setting or has any idea how I can verify my SPIR-V code in a better way, without checking all 700 lines of code manually.
I don't thinkt the problem is there, but anyway here is the c++ host code:
#include "vulkan/vulkan.hpp"
#include <iostream>
#include <fstream>
#include <vector>
#define BAIL_ON_BAD_RESULT(result) \
if (VK_SUCCESS != (result)) \
{ \
fprintf(stderr, "Failure at %u %s\n", __LINE__, __FILE__); \
exit(-1); \
}
VkResult vkGetBestComputeQueueNPH(vk::PhysicalDevice &physicalDevice, uint32_t &queueFamilyIndex)
{
auto properties = physicalDevice.getQueueFamilyProperties();
int i = 0;
for (auto prop : properties)
{
vk::QueueFlags maskedFlags = (~(vk::QueueFlagBits::eTransfer | vk::QueueFlagBits::eSparseBinding) & prop.queueFlags);
if (!(vk::QueueFlagBits::eGraphics & maskedFlags) && (vk::QueueFlagBits::eCompute & maskedFlags))
{
queueFamilyIndex = i;
return VK_SUCCESS;
}
i++;
}
i = 0;
for (auto prop : properties)
{
vk::QueueFlags maskedFlags = (~(vk::QueueFlagBits::eTransfer | vk::QueueFlagBits::eSparseBinding) & prop.queueFlags);
if (vk::QueueFlagBits::eCompute & maskedFlags)
{
queueFamilyIndex = i;
return VK_SUCCESS;
}
i++;
}
return VK_ERROR_INITIALIZATION_FAILED;
}
int main(int argc, const char *const argv[])
{
(void)argc;
(void)argv;
try
{
// initialize the vk::ApplicationInfo structure
vk::ApplicationInfo applicationInfo("VecAdd", 1, "Vulkan.hpp", 1, VK_API_VERSION_1_1);
// initialize the vk::InstanceCreateInfo
std::vector<char *> layers = {
"VK_LAYER_LUNARG_api_dump",
"VK_LAYER_KHRONOS_validation"
};
vk::InstanceCreateInfo instanceCreateInfo({}, &applicationInfo, static_cast<uint32_t>(layers.size()), layers.data());
// create a UniqueInstance
vk::UniqueInstance instance = vk::createInstanceUnique(instanceCreateInfo);
auto physicalDevices = instance->enumeratePhysicalDevices();
for (auto &physicalDevice : physicalDevices)
{
auto props = physicalDevice.getProperties();
// get the QueueFamilyProperties of the first PhysicalDevice
std::vector<vk::QueueFamilyProperties> queueFamilyProperties = physicalDevice.getQueueFamilyProperties();
uint32_t computeQueueFamilyIndex = 0;
// get the best index into queueFamiliyProperties which supports compute and stuff
BAIL_ON_BAD_RESULT(vkGetBestComputeQueueNPH(physicalDevice, computeQueueFamilyIndex));
std::vector<char *>extensions = {"VK_EXT_external_memory_host", "VK_KHR_shader_float16_int8"};
// create a UniqueDevice
float queuePriority = 0.0f;
vk::DeviceQueueCreateInfo deviceQueueCreateInfo(vk::DeviceQueueCreateFlags(), static_cast<uint32_t>(computeQueueFamilyIndex), 1, &queuePriority);
vk::StructureChain<vk::DeviceCreateInfo, vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceShaderFloat16Int8Features> createDeviceInfo = {
vk::DeviceCreateInfo(vk::DeviceCreateFlags(), 1, &deviceQueueCreateInfo, 0, nullptr, static_cast<uint32_t>(extensions.size()), extensions.data()),
vk::PhysicalDeviceFeatures2(),
vk::PhysicalDeviceShaderFloat16Int8Features()
};
createDeviceInfo.get<vk::PhysicalDeviceFeatures2>().features.setShaderInt64(true);
createDeviceInfo.get<vk::PhysicalDeviceShaderFloat16Int8Features>().setShaderInt8(true);
vk::UniqueDevice device = physicalDevice.createDeviceUnique(createDeviceInfo.get<vk::DeviceCreateInfo>());
auto memoryProperties2 = physicalDevice.getMemoryProperties2();
vk::PhysicalDeviceMemoryProperties const &memoryProperties = memoryProperties2.memoryProperties;
const int32_t bufferLength = 16384;
const uint32_t bufferSize = sizeof(int32_t) * bufferLength;
// we are going to need two buffers from this one memory
const vk::DeviceSize memorySize = bufferSize * 3;
// set memoryTypeIndex to an invalid entry in the properties.memoryTypes array
uint32_t memoryTypeIndex = VK_MAX_MEMORY_TYPES;
for (uint32_t k = 0; k < memoryProperties.memoryTypeCount; k++)
{
if ((vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent) & memoryProperties.memoryTypes[k].propertyFlags &&
(memorySize < memoryProperties.memoryHeaps[memoryProperties.memoryTypes[k].heapIndex].size))
{
memoryTypeIndex = k;
std::cout << "found memory " << memoryTypeIndex + 1 << " out of " << memoryProperties.memoryTypeCount << std::endl;
break;
}
}
BAIL_ON_BAD_RESULT(memoryTypeIndex == VK_MAX_MEMORY_TYPES ? VK_ERROR_OUT_OF_HOST_MEMORY : VK_SUCCESS);
auto memory = device->allocateMemoryUnique(vk::MemoryAllocateInfo(memorySize, memoryTypeIndex));
auto in_buffer = device->createBufferUnique(vk::BufferCreateInfo(vk::BufferCreateFlags(), bufferSize, vk::BufferUsageFlagBits::eStorageBuffer, vk::SharingMode::eExclusive));
device->bindBufferMemory(in_buffer.get(), memory.get(), 0);
// create a DescriptorSetLayout
std::vector<vk::DescriptorSetLayoutBinding> descriptorSetLayoutBinding{
{0, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eCompute}};
vk::UniqueDescriptorSetLayout descriptorSetLayout = device->createDescriptorSetLayoutUnique(vk::DescriptorSetLayoutCreateInfo(vk::DescriptorSetLayoutCreateFlags(), static_cast<uint32_t>(descriptorSetLayoutBinding.size()), descriptorSetLayoutBinding.data()));
std::cout << "Memory bound" << std::endl;
std::ifstream myfile;
myfile.open("shaders/MainV.spv", std::ios::ate | std::ios::binary);
if (!myfile.is_open())
{
std::cout << "File not found" << std::endl;
return EXIT_FAILURE;
}
auto size = myfile.tellg();
std::vector<unsigned int> shader_spv(size / sizeof(unsigned int));
myfile.seekg(0);
myfile.read(reinterpret_cast<char *>(shader_spv.data()), size);
myfile.close();
std::cout << "Shader size: " << shader_spv.size() << std::endl;
auto shaderModule = device->createShaderModuleUnique(vk::ShaderModuleCreateInfo(vk::ShaderModuleCreateFlags(), shader_spv.size() * sizeof(unsigned int), shader_spv.data()));
// create a PipelineLayout using that DescriptorSetLayout
vk::UniquePipelineLayout pipelineLayout = device->createPipelineLayoutUnique(vk::PipelineLayoutCreateInfo(vk::PipelineLayoutCreateFlags(), 1, &descriptorSetLayout.get()));
vk::ComputePipelineCreateInfo computePipelineInfo(
vk::PipelineCreateFlags(),
vk::PipelineShaderStageCreateInfo(
vk::PipelineShaderStageCreateFlags(),
vk::ShaderStageFlagBits::eCompute,
shaderModule.get(),
"_ZTSZZ4mainENK3$_0clERN2cl4sycl7handlerEE6VecAdd"),
pipelineLayout.get());
auto pipeline = device->createComputePipelineUnique(nullptr, computePipelineInfo);
auto descriptorPoolSize = vk::DescriptorPoolSize(vk::DescriptorType::eStorageBuffer, 2);
auto descriptorPool = device->createDescriptorPool(vk::DescriptorPoolCreateInfo(vk::DescriptorPoolCreateFlags(), 1, 1, &descriptorPoolSize));
auto commandPool = device->createCommandPoolUnique(vk::CommandPoolCreateInfo(vk::CommandPoolCreateFlags(), computeQueueFamilyIndex));
auto commandBuffer = std::move(device->allocateCommandBuffersUnique(vk::CommandBufferAllocateInfo(commandPool.get(), vk::CommandBufferLevel::ePrimary, 1)).front());
commandBuffer->begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlags(vk::CommandBufferUsageFlagBits::eOneTimeSubmit)));
commandBuffer->bindPipeline(vk::PipelineBindPoint::eCompute, pipeline.get());
commandBuffer->dispatch(bufferSize / sizeof(int32_t), 1, 1);
commandBuffer->end();
auto queue = device->getQueue(computeQueueFamilyIndex, 0);
vk::SubmitInfo submitInfo(0, nullptr, nullptr, 1, &commandBuffer.get(), 0, nullptr);
queue.submit(1, &submitInfo, vk::Fence());
queue.waitIdle();
printf("all done\nWoohooo!!!\n\n");
}
}
catch (vk::SystemError &err)
{
std::cout << "vk::SystemError: " << err.what() << std::endl;
exit(-1);
}
catch (std::runtime_error &err)
{
std::cout << "std::runtime_error: " << err.what() << std::endl;
exit(-1);
}
catch (...)
{
std::cout << "unknown error\n";
exit(-1);
}
return EXIT_SUCCESS;
}
Well after checking out line per line it showed that the problem is when working with pointers of pointers. For me it is still not clear from the specification that it is not allowed, but it is understandable that it does not work with logical pointers.
Still the behaviour is strange that the validator is not able to note that and that compiling the SPIRV code crashes instead of throwing a clear error message.
So in the end, it was the Shader code which was wrong.

*** Error in `./text_buffer': corrupted double-linked list: 0x089cbd98 **

I'm trying to make the app using FreeTDS. Following are my code
/*
* Purpose: Test to see if row buffering and blobs works correctly.
* Functions: dbbind dbnextrow dbopen dbresults dbsqlexec dbgetrow
*/
#include "common.h"
#include "stdio.h"
#include<stdlib.h>
#include "readline/readline.h"
#include "readline/history.h"
#include "string.h"
int
main(int argc, char **argv)
{
char failed;
int hasil;
char ch;
char* r = malloc(30);
LOGINREC *login;
DBPROCESS *dbproc;
int i;
int p = 0;
char teststr[1024];
DBINT testint;
read_login_info(argc, argv);
fprintf(stdout, "Starting %s\n", argv[0]);
/* Fortify_EnterScope(); */
while(1)
{
char qrcode[50];
char perintahsql[100] = "select * from REF_COBA where id=";
char *alokasi="";
while(ch != '\n') // terminates if user hit enter
{
ch = getchar();
qrcode[p] = ch;
p++;
}
qrcode[p]='\0';
strcpy(r,qrcode);
alokasi = strsep(&r, ",");
strcpy(r,"");
p=0;
ch = "";
dbinit();
dberrhandle(syb_err_handler);
dbmsghandle(syb_msg_handler);
fprintf(stdout, "About to logon\n");
login = dblogin();
DBSETLPWD(login, PASSWORD);
DBSETLUSER(login, USER);
DBSETLAPP(login, "text_buffer");
//DBSETLHOST(login, "ntbox.dntis.ro");
DBSETLHOST(login, "192.168.1.9");
fprintf(stdout, "About to open\n");
dbproc = dbopen(login, SERVER);
if (strlen(DATABASE))
dbuse(dbproc, DATABASE);
dbloginfree(login);
#ifdef MICROSOFT_DBLIB
dbsetopt(dbproc, DBBUFFER, "100");
#else
dbsetopt(dbproc, DBBUFFER, "100", 0);
#endif
dbcmd(dbproc, strcat(perintahsql,alokasi));
dbsqlexec(dbproc);
if (dbresults(dbproc) != SUCCEED)
{
failed = 1;
fprintf(stdout, "Was expecting a result set.");
exit(1);
}
fprintf(stdout, "select\n");
for (i = 1; i <= dbnumcols(dbproc); i++)
printf("col %d is %s\n", i, dbcolname(dbproc, i));
fprintf(stdout, "setelah for\n");
dbbind(dbproc, 1, INTBIND, 0, (BYTE *) & testint);
dbbind(dbproc, 2, CHARBIND, 0, (BYTE *) teststr);
for (i = 1; i < 2; i++)
{
char expected[1024];
sprintf(expected, "row %03d", i);
if (i % 100 == 0)
{
dbclrbuf(dbproc, 100);
}
if (REG_ROW != dbnextrow(dbproc))
{
failed = 1;
fprintf(stderr, "Failed. Expected a row\n");
//exit(1);
}
else
{
fprintf(stdout, "jalanin usb\n");
printf("Read a row of data -> %d %s\n", (int) testint, teststr);
hasil = system("/opt/usb1rc_linux USB1REL-172 R");
sleep(2);
hasil = system("/opt/usb1rc_linux USB1REL-172 r");
}
}
dbfreebuf(dbproc);
dbexit();
}
return 0;
}
I modified the source from FreeTDS, after compilation there are some warning
bash-4.2# make text_buffer
CC text_buffer.o
text_buffer.c: In function 'main':
text_buffer.c:54:8: warning: assignment makes integer from pointer without a cast [enabled by default]
ch = "";
^
text_buffer.c:18:7: warning: variable 'hasil' set but not used [-Wunused-but-set-variable]
int hasil;
^
text_buffer.c:17:8: warning: variable 'failed' set but not used [-Wunused-but-set-variable]
char failed;
^
CC common.o
CCLD text_buffer
I execute the program without error. This program will check input from user then run the sql command. The format of input shall be , e.g 123456,john doe then press enter. After 50-60 times of input, the double-linked list error will happen.
could anybody help why the error happen?

GNU Radio circular buffer manipulation

I encountered the following error
gr::log :WARN: tpb_thread_body - asynchronous message buffer overflowing, dropping message
Out of serendipity, I ran into this GNU Radio presentation on
Youtube.
The presenter mentioned an OOT block he called "buffer" that is capable of eliminating the "buffer overflowing" error. Apparently, this block plays with different sample rates and the so-called "circular buffers". I haven't worked with circular buffers myself. Any ideas on circular buffers or any hints on how to build this buffer block are welcome.
EDIT
Below is the flowgraph that generates the error. As it was suggested in the comments, the culprits could be the message processing blocks (red-circled) namely generateCADU (for generating standard CCSDS frames) and processCADU (for extracting CADUs from a data stream).
The implementation file of the generateCADU block is given below
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gnuradio/io_signature.h>
#include "generateCADU_impl.h"
#include "fec/ReedSolomon/ReedSolomon.h"
#include "fec/Scrambler/Scrambler.h"
namespace gr {
namespace ccsds {
generateCADU::sptr
generateCADU::make(int frameLength,std::string sync, int scramble, int rs, int intDepth)
{
return gnuradio::get_initial_sptr
(new generateCADU_impl(frameLength, sync, scramble, rs, intDepth));
}
/*
* The private constructor
*/
generateCADU_impl::generateCADU_impl(int frameLength,std::string sync, int scramble, int rs, int intDepth)
: gr::sync_block("generateCADU",
gr::io_signature::make(1, 1, sizeof(unsigned char)),
gr::io_signature::make(0, 0, 0)),
d_frameLength(frameLength),d_scramble(scramble == 1),d_rs(rs >= 1), d_basis(rs >= 2), d_intDepth(intDepth)
{
set_output_multiple(d_frameLength);
//Registering output port
message_port_register_out(pmt::mp("out"));
d_sync = parse_string(sync);
}
/*
* Our virtual destructor.
*/
generateCADU_impl::~generateCADU_impl()
{
}
unsigned char
generateCADU_impl::parse_hex(char c)
{
if ('0' <= c && c <= '9') return c - '0';
if ('A' <= c && c <= 'F') return c - 'A' + 10;
if ('a' <= c && c <= 'f') return c - 'a' + 10;
std::abort();
}
std::vector<unsigned char>
generateCADU_impl::parse_string(const std::string & s)
{
if (s.size() % 2 != 0) std::abort();
std::vector<unsigned char> result(s.size() / 2);
for (std::size_t i = 0; i != s.size() / 2; ++i)
result[i] = 16 * parse_hex(s[2 * i]) + parse_hex(s[2 * i + 1]);
return result;
}
int
generateCADU_impl::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
const unsigned char *in = (const unsigned char *) input_items[0];
//Reed-Solomon and Scrambler objects
ReedSolomon RS(16,d_intDepth,d_basis);// False = conventional, True = dual-basis
Scrambler S;
//Buffers
unsigned char *frameBuffer1 = (unsigned char*)malloc(d_frameLength*sizeof(unsigned char));
std::vector<unsigned char> frameBuffer2;
//The work function engine
for(int i = 0; (i + d_frameLength) < noutput_items; i += d_frameLength)
{
//Copying data from input stream
memcpy(frameBuffer1,in + i + d_frameLength,d_frameLength);
//Copying frame into std::vector buffer
frameBuffer2.insert(frameBuffer2.begin(),frameBuffer1, frameBuffer1 + d_frameLength);
//Optional scrambling and Reed-Solomon
if (d_rs) RS.Encode_RS(frameBuffer2);
if (d_scramble) S.Scramble(frameBuffer2);
//Insert sync word
frameBuffer2.insert(frameBuffer2.begin(), d_sync.begin(), d_sync.end());
//Transmitting PDU
pmt::pmt_t pdu(pmt::cons(pmt::PMT_NIL,pmt::make_blob(frameBuffer2.data(),frameBuffer2.size())));
message_port_pub(pmt::mp("out"), pdu);
//Clear buffer
frameBuffer2.clear();
}
// Tell runtime system how many output items we produced.
return noutput_items;
}
} /* namespace ccsds */
} /* namespace gr */
And here is the processCADU block. This block uses tags generated by the synchronizeCADU (which is simply a wrapper for the correlate_access_tag block) to extract CADUs
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gnuradio/io_signature.h>
#include "processCADU_impl.h"
#include "fec/ReedSolomon/ReedSolomon.h"
#include "fec/Scrambler/Scrambler.h"
namespace gr {
namespace ccsds {
processCADU::sptr
processCADU::make(int frameLength, int scramble, int rs, int intDepth, std::string tagName)
{
return gnuradio::get_initial_sptr
(new processCADU_impl(frameLength, scramble, rs, intDepth, tagName));
}
/*
* The private constructor
*/
processCADU_impl::processCADU_impl(int frameLength, int scramble, int rs, int intDepth, std::string tagName)
: gr::sync_block("processCADU",
gr::io_signature::make(1, 1, sizeof(unsigned char)),
gr::io_signature::make(0, 0, 0)),
d_frameLength(frameLength),d_scramble(scramble == 1),d_rs(rs >= 1), d_basis(rs >= 2), d_intDepth(intDepth)
{
//Multiple input
set_output_multiple(d_frameLength * 8);
//Registering output port
message_port_register_out(pmt::mp("out"));
if (d_rs) d_frameLength += 32 * d_intDepth;
//SEtting tag name
key = pmt::mp(tagName);
}
/*
* Our virtual destructor.
*/
processCADU_impl::~processCADU_impl()
{
delete d_pack;
}
int
processCADU_impl::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
const unsigned char *in = (const unsigned char *) input_items[0];
unsigned char *out = (unsigned char *) output_items[0];
void *msg_data = NULL;
unsigned char frame_data[d_frameLength];
unsigned char frame_len = 0;
std::vector<unsigned char> frameBuffer;
//Reed-Solomon and Scrambler objects
ReedSolomon RS(16,d_intDepth,d_basis);// False = conventional, True = dual-basis
std::vector<int> errors;//errors.push_back(0);
Scrambler S;
d_tags.clear();
d_pack = new blocks::kernel::pack_k_bits(8);
this->get_tags_in_window(d_tags, 0, 0, noutput_items,key);
for(d_tags_itr = d_tags.begin(); d_tags_itr != d_tags.end(); d_tags_itr++) {
// Check that we have enough data for a full frame
if ((d_tags_itr->offset - this->nitems_read(0)) > (noutput_items - (d_frameLength) * 8))
{
return (d_tags_itr->offset - this->nitems_read(0) - 1);
}
//Pack bits into bytes
d_pack->pack(frame_data, &in[d_tags_itr->offset - this->nitems_read(0)], d_frameLength);
//Copying frame into std::vector buffer
frameBuffer.insert(frameBuffer.begin(),frame_data, frame_data + d_frameLength);
//Optional scrambling and Reed-Solomon
if (d_scramble) S.Scramble(frameBuffer);
//if (d_rs) RS.Decode_RS(frameBuffer,errors);
//If there is Reed-Solomon decoding
if(d_rs)
{
RS.Decode_RS(frameBuffer,errors);
if (RS.Success(errors)) // Success
{
//std::cout << "Success" << std::endl;
pmt::pmt_t pdu(pmt::cons(pmt::PMT_NIL,pmt::make_blob(frameBuffer.data(),frameBuffer.size())));
message_port_pub(pmt::mp("out"), pdu);
/*for(int i=0; i < errors.size(); i++)
{
//std::cout << "Number of Errors : " << errors.at(i) << std::endl << std::endl;
}*/
}
else // Failure
{
std::cout << "RS failure" << std::endl;
}
}
else{
pmt::pmt_t pdu(pmt::cons(pmt::PMT_NIL,pmt::make_blob(frameBuffer.data(),frameBuffer.size())));
message_port_pub(pmt::mp("out"), pdu);
}
//Clear buffers
frameBuffer.clear();
errors.clear();
}
// Tell runtime system how many output items we produced.
return noutput_items;
}
} /* namespace ccsds */
} /* namespace gr */
Regards,
M
Thanks to #MarcusMüller suggestion, using the tagged_stream paradigma as opposed to PDUs solved the problem. I was able to transmit 47 terabytes of data without any problems. Below is the code for the newly implemented block.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gnuradio/io_signature.h>
#include "genCADU_impl.h"
namespace gr {
namespace ccsds {
genCADU::sptr
genCADU::make(int frameLength,std::string sync, int scramble, int rs, int intDepth, std::string len_tag_key)
{
return gnuradio::get_initial_sptr
(new genCADU_impl(frameLength, sync, scramble, rs, intDepth, len_tag_key));
}
/*
* The private constructor
*/
genCADU_impl::genCADU_impl(int frameLength,std::string sync, int scramble, int rs, int intDepth, std::string len_tag_key)
: gr::tagged_stream_block("genCADU",
gr::io_signature::make(1, 1, sizeof(unsigned char)),
gr::io_signature::make(1, 1, sizeof(unsigned char)),len_tag_key),
d_frameLength(frameLength),d_scramble(scramble == 1),d_rs(rs >= 1), d_basis(rs >= 2), d_intDepth(intDepth)
{
//Synchronization pattern
d_sync = parse_string(sync);
//Reed-Solomon and Scrambler objects
RS = new ReedSolomon(16,d_intDepth,d_basis);// False = conventional, True = dual-basis
S = new Scrambler();
}
/*
* Our virtual destructor.
*/
genCADU_impl::~genCADU_impl()
{
delete RS;
delete S;
}
int
genCADU_impl::calculate_output_stream_length(const gr_vector_int &ninput_items)
{
int noutput_items = (d_rs) ? d_frameLength + 32*d_intDepth + d_sync.size() : d_frameLength + d_sync.size();
return noutput_items ;
}
unsigned char
genCADU_impl::parse_hex(char c)
{
if ('0' <= c && c <= '9') return c - '0';
if ('A' <= c && c <= 'F') return c - 'A' + 10;
if ('a' <= c && c <= 'f') return c - 'a' + 10;
std::abort();
}
std::vector<unsigned char>
genCADU_impl::parse_string(const std::string & s)
{
if (s.size() % 2 != 0) std::abort();
std::vector<unsigned char> result(s.size() / 2);
for (std::size_t i = 0; i != s.size() / 2; ++i)
result[i] = 16 * parse_hex(s[2 * i]) + parse_hex(s[2 * i + 1]);
return result;
}
int
genCADU_impl::work (int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
const unsigned char *in = (const unsigned char *) input_items[0];
unsigned char *out = (unsigned char *) output_items[0];
int total_len;
//Copy pdu from circular buffer to local buffer
buffer.insert(buffer.end(), in, in + d_frameLength);
//Optional scrambling and Reed-Solomon. TO DO: Turbo and LDPC
if (d_rs) RS->Encode_RS(buffer);
if (d_scramble) S->Scramble(buffer);
//Insert sync word
buffer.insert(buffer.begin(), d_sync.begin(), d_sync.end());
//Copy from local buffer to circular buffer
std::copy(buffer.begin(),buffer.end(),out);
//Clear the local buffer
total_len = buffer.size();
buffer.clear();
// Tell runtime system how many output items we produced.
return total_len;
}
} /* namespace ccsds */
} /* namespace gr */
Regards,
M.

How to generate binary tree dot file for Graphviz from C++

I have implemented a Binary Search Tree in C++ which support dynamically creating and deleting nodes. To visualize the tree, I firstly tried displaying edges with / and \. However, this gives really awful visualization, as the position of / and \ needs to be calculated precisely. The current figures are as follows:
So I found a tool called Graphviz. The raw language supported by Graphviz is dot language, which I am not familiar with.
I read the documentation and found the dot language easy to write and read, but I still want to use my C++ code to generate the tree as this contains much content such as inserting according to user's input.
Is there any chance to use some function to generate the dot file?
The code of my binary tree:
//BTNode.h
#include <iostream>
using namespace std;
template<class T>
struct BTNode{
BTNode(){
lChild = rChild = NULL;
}
BTNode(const T& x){
element = x;
lChild = rChild = NULL;
}
BTNode(const T& x, BTNode<T>* l, BTNode<T>* r){
element = x;
lChild = l;
rChild = r;
}
T element;
int digit, row;
BTNode<T>* lChild, *rChild;
};
//BSTree.h
#include"ResultCode.h"
#include "BTNode.h"
#include "seqqueue.h"
#include <math.h>
template <class T>
class BSTree
{
public:
BSTree(){ root = NULL; }
ResultCode SearchByRecursion(T& x)const;
ResultCode Insert(T& x);
ResultCode Remove(T& x);
void InOrder(void(*Visit)(T& x));
ResultCode SearchByIteration(T& x);
void GradeOrder(void(*Visit)(T &x), BTNode<T> *t, int height);
BTNode<T>* root;
void printSpace(int num);
int GetHeight();
int GetHeight(BTNode<T> *t);
int **A;
private:
ResultCode SearchByRecursion(BTNode<T> *p, T& x)const;
void InOrder(void(*Visit)(T& x), BTNode<T> *t);
};
template <class T>
ResultCode BSTree<T>::SearchByRecursion(T &x)const{
return SearchByRecursion(root, x);
}
template <class T>
ResultCode BSTree<T>::SearchByRecursion(BTNode<T> *p, T& x)const{
if (!p) return NotPresent;
else if (x < p->element) return SearchByRecursion(p->lChild, x);
else if (x > p->element) return SearchByRecursion(p->rChild, x);
else{
x = p->element;
return Success;
}
}
template <class T>
ResultCode BSTree<T>::SearchByIteration(T& x){
BTNode<T> *p = root;
while (p)
if (x < p->element) p = p->lChild;
else if (x > p->element) p = p->rChild;
else{
x = p->element;
return Success;
}
return NotPresent;
}
template<class T>
ResultCode BSTree<T>::Insert(T& x){
BTNode<T> *p = root, *q = NULL;
while (p){
q = p;
if (x < p->element) p = p->lChild;
else if (x > p->element) p = p->rChild;
else { x = p->element; return Duplicate; }
}
p = new BTNode<T>(x);
if (!root) root = p;
else if (x < q->element) q->lChild = p;
else q->rChild = p;
return Success;
}
template <class T>
ResultCode BSTree<T>::Remove(T& x){
BTNode<T> *c, *s, *r, *p = root, *q = NULL;
while (p && p->element != x){
q = p;
if (x < p->element) p = p->lChild;
else p = p->rChild;
}
if (!p) return NotPresent;
x = p->element;
if (p->lChild&&p->rChild)
{
s = p->rChild;
r = p;
while (s->lChild){
r = s; s = s->lChild;
}
p->element = s->element;
p = s; q = r;
}
if (p->lChild)
c = p->lChild;
else c = p->rChild;
if (p == root)
root = c;
else if (p == q->lChild)
q->lChild = c;
else q->rChild = c;
delete p;
return Success;
}
template <class T>
void BSTree<T>::InOrder(void(*Visit)(T &x)){
InOrder(Visit, root);
}
template <class T>
void BSTree<T>::InOrder(void(*Visit)(T &x), BTNode<T> *t){
if (t){
InOrder(Visit, t->lChild);
Visit(t->element);
InOrder(Visit, t->rChild);
}
}
template <class T>
void BSTree<T>::GradeOrder(void(*Visit)(T &x), BTNode<T> *t, int height)
{
A = new int*[height];
for (int i = 0; i < height; i++){
A[i] = new int[(int)pow(2, height) - 1];
}
for (int i = 0; i < height; i++)
for (int j = 0; j < (int)pow(2, height) - 1; j++){
A[i][j] = -1;
}
SeqQueue<BTNode<T>*> OrderQueue(10);
BTNode<T> * loc = t;
loc->row = 0;
loc->digit = 0;
if (loc){
OrderQueue.EnQueue(loc);
A[loc->row][loc->digit] = loc->element;
}
while (!OrderQueue.IsEmpty())
{
OrderQueue.Front(loc);
OrderQueue.DeQueue();
if (loc->lChild)
{
A[(loc->row) + 1][2 * (loc->digit)] = loc->lChild->element;
loc->lChild->row = (loc->row) + 1;
(loc->lChild->digit) = (loc->digit) * 2;
OrderQueue.EnQueue(loc->lChild);
}
if (loc->rChild)
{
A[(loc->row) + 1][2 * (loc->digit) + 1] = loc->rChild->element;
loc->rChild->row = (loc->row) + 1;
(loc->rChild->digit) = (loc->digit) * 2 + 1;
OrderQueue.EnQueue(loc->rChild);
}
}
cout << endl;
int total = (int)(pow(2, height)) - 1;
for (int i = 0; i < height; i++){
if (i != 0){
cout << endl;
}
int space1 = (total / (int)(pow(2, i + 1)));
int space2;
if (i == 0){
space2 = 0;
}
else{
space2 = (total - 2 * space1 - (int)pow(2, i)) / (int)(pow(2, i) - 1);
}
printSpace(space1);
for (int j = 0; j < (int)pow(2, i); j++){
if (A[i][j] != -1){
cout << A[i][j];
}
else{
cout << " ";
}
printSpace(space2);
}
printSpace(space1);
cout << endl;
}
}
template <class T>
void BSTree<T>::printSpace(int num){
for (int i = 0; i < num; i++){
cout << " ";
}
}
template<class T>
int BSTree<T>::GetHeight()
{
return GetHeight(root);
}
template<class T>
int BSTree<T>::GetHeight(BTNode<T> *t)
{
if (!t)return 0;
if ((!t->lChild) && (!t->rChild)) return 1;
int lHeight = GetHeight(t->lChild);
int rHeight = GetHeight(t->rChild);
return (lHeight > rHeight ? lHeight : rHeight) + 1;
}
template <class T>
void Visit(T& x){
cout << x << " ";
}
//main.cpp
#include <iostream>
#include "BSTree4.h"
#include<Windows.h>
int getDigit(int x);
int main(){
BSTree<int> bt;
int number;
// char choice;
cout << "Welcome to BSTree System, to begin with, you need to create a tree!(Press enter to continue...)" << endl;
getchar();
cout << "Please enter the size of the Binary Search Tree:";
cin >> number;
int *ToBeInserted = new int[number];
cout << "Enter the number of each Node(size:" << number << "):";
for (int i = 0; i < number; i++){
cin >> ToBeInserted[i];
}
cout << "OK,now the tree will be created!" << endl;
for (int i = 0; i < number; i++){
cout << "Inserting Node " << i;
for (int k = 0; k < 3; k++){
cout << ".";
//Sleep(200);
}
showResultCode(bt.Insert(ToBeInserted[i]));
//Sleep(500);
}
cout << "Done." << endl;
//Sleep(500);
int height = bt.GetHeight();
bt.GradeOrder(Visit, bt.root,height);
int a;
cout << "please enter the number to search:";
cin>>a;
showResultCode(bt.SearchByRecursion(a));
bt.GradeOrder(Visit, bt.root,height);
if (bt.SearchByRecursion(a) == 7){
cout << "Now delete the number" << "..." << endl;
showResultCode(bt.Remove(a));
bt.GetHeight();
cout << "Deleted!Now the tree is:" << endl;
bt.GradeOrder(Visit, bt.root, height);
bt.InOrder(Visit);
cout << endl;
}
return 0;
}
//resultcode.h
#include<iostream>
using namespace std;
enum ResultCode{ NoMemory, OutOfBounds, Underflow, Overflow, Failure,
NotPresent, Duplicate, Success };
void showResultCode(ResultCode result)
{
int r = (int)result;
switch (result)
{
case 0:cout << "NoMemory" << endl; break;
case 1:cout << "OutOfBounds" << endl; break;
case 2:cout << "Underflow" << endl; break;
case 3:cout << "Overflow" << endl; break;
case 4:cout << "Failure" << endl; break;
case 5:cout << "NotPresent" << endl; break;
case 6:cout << "Duplicate" << endl; break;
case 7:cout << "Success" << endl; break;
default: cout << "Exception occured:unknown resultcode" << endl;
}
}
Update: I have solved the problem myself, check the answer below.
The key elements in dot language file in this problem are nodes and edges. Basically the dot file structure for a binary tree would be like the following:
digraph g {
//all the nodes
node0[label="<f0>|<f1> value |<f2>"]
node1[label="<f0>|<f1> value |<f2>"]
node2[label="<f0>|<f1> value |<f2>"]
...
//all the edges
"node0":f2->"node4":f1;
"node0":f0->"node1":f1;
"node1":f0->"node2":f1;
"node1":f2->"node3":f1;
...
}
The following output of the dot file can be used to understand the structure:
Explanation for the dot file:
For the node part node0[label="<f0>|<f1> value |<f2>"] means the node called node0 has three parts: <f0> is the left part, <f1> is the middle part with a value, <f2> is the right part. This just corresponds to leftchild, value and rightchild in a binary node.
For the edges part, "node0":f2->"node4":f1; means the right part of node0(i.e.<f2>) points to the middle part of node4 (i.e. <f1>).
Therefore, the way to generate the dot file is simply through a traverse of a binary tree. Any method is fine. (BFS,DFS...) All we need is to add the code to write the nodes and corresponding edges into file when we do the traverse. I personally used BFS with level order traverse of a binary tree to implement which is shown below as a function called showTree.
void showTree(BSTree<int> &bst,int total,int *Inserted){
char filename[] = "D:\\a.gv"; // filename
ofstream fout(filename);
fout << "digraph g{" << endl;
fout << "node [shape = record,height = .1];" << endl;
SeqQueue<BTNode<int>*> OrderQueue(1000);
BTNode<int> * loc = bst.root;
loc->row = 0;
loc->digit = 0;
int num = 0;
if (loc){
OrderQueue.EnQueue(loc);
loc->ID = num++;
fout << " node" << loc->ID << "[label = \"<f0> |<f1>" << loc->element << "|<f2>\"];" << endl;
}
while (!OrderQueue.IsEmpty())
{
OrderQueue.Front(loc);
OrderQueue.DeQueue();
if (loc->lChild)
{
loc->lChild->row = (loc->row) + 1;
(loc->lChild->digit) = (loc->digit) * 2;
OrderQueue.EnQueue(loc->lChild);
loc->lChild ->ID= (num++);
fout << " node" << loc->lChild->ID << "[label = \"<f0> |<f1>" << loc->lChild->element << "|<f2>\"];" << endl;
//cout << loc->ID;
}
if (loc->rChild)
{
loc->rChild->row = (loc->row) + 1;
(loc->rChild->digit) = (loc->digit) * 2 + 1;
OrderQueue.EnQueue(loc->rChild);
loc->rChild->ID = (num++);
fout << " node" << loc->rChild->ID << "[label = \"<f0> |<f1>" << loc->rChild->element << "|<f2>\"];" << endl;
//cout << loc->ID;
}
}
//begin to draw!
SeqQueue<BTNode<int>*> OrderQueue2(1000);
BTNode<int> * loc2 = bst.root;
loc2->row = 0;
loc2->digit = 0;
if (loc2){
OrderQueue2.EnQueue(loc2);
}
while (!OrderQueue2.IsEmpty())
{
OrderQueue2.Front(loc2);
OrderQueue2.DeQueue();
if (loc2->lChild)
{
loc2->lChild->row = (loc2->row) + 1;
(loc2->lChild->digit) = (loc2->digit) * 2;
OrderQueue2.EnQueue(loc2->lChild);
cout << "\"node" << loc2->ID << "\":f0->\"node" << loc2->lChild->ID << "\":f1;" << endl;
cout << loc2->lChild->element << endl;
fout << "\"node" << loc2->ID << "\":f0->\"node" << loc2->lChild->ID << "\":f1;" << endl;
}
if (loc2->rChild)
{
loc2->rChild->row = (loc2->row) + 1;
(loc2->rChild->digit) = (loc2->digit) * 2 + 1;
OrderQueue2.EnQueue(loc2->rChild);
cout << "\"node" << loc2->ID << "\":f2->\"node" << loc2->rChild->ID << "\":f1;" << endl;
cout << loc2->rChild->element << endl;
fout << "\"node" << loc2->ID << "\":f2->\"node" << loc2->rChild->ID << "\":f1;" << endl;
}
}
fout << "}" << endl;
}
And the final output: