void CombinedProfile::printDrift(const CombinedProfile& other, llvm::raw_ostream& stream) const { // build union of non-zero histograms IndexSet I; for(unsigned i = 0, E = size(); i < E; ++i) if( (_histograms[i] != NULL) && _histograms[i]->nonZero() ) I.insert(i); for(unsigned i = 0, E = other.size(); i < E; ++i) if( (other._histograms[i] != NULL) && other._histograms[i]->nonZero() ) I.insert(i); if(I.size() == 0) errs() << "Warning: no histograms\n"; // Compute and print drift stream << "#" << getNameStr() << "Index\t0-out\t0-in\n"; for(IndexSet::iterator i = I.begin(), E = I.end(); i != E; ++i) { // check for 0-overlap (100% drift) cases if( (*i > size()) || (*i > other.size()) || (_histograms[*i] == NULL) || (other._histograms[*i] == NULL) || !_histograms[*i]->nonZero() || !other._histograms[*i]->nonZero() ) { errs() << "Warning: histogram " << *i << " only exists in one profile!\n"; stream << *i << "\t1.0\t1.0\n"; continue; } CPHistogram* h1 = _histograms[*i]; CPHistogram* h2 = other._histograms[*i]; if( h1->isPoint() && h2->isPoint() && (h1->min() != h2->min())) { errs() << "Warning: histogram " << *i << " has different point values\n"; stream << *i << "\t1.0\t1.0\n"; continue; } // finally, no exceptional situations! stream << *i << "\t" << 1-h1->overlap(*h2, false) << "\t" << 1-h1->overlap(*h2, true) << "\n"; } }
void Thread::removeOperator(const Operator* op) { typedef std::set< std::vector<Input>::iterator > IndexSet; if (op == 0) throw WrongArgument("Operator must not be null."); m_thread->removeOperator(op); IndexSet toBeErased; for(std::vector<Input>::iterator iter1 = m_inputSequence.begin(); iter1 != m_inputSequence.end(); ++iter1) { if((*iter1).op() == op) toBeErased.insert(iter1); } for(IndexSet::reverse_iterator iter2 = toBeErased.rbegin(); iter2 != toBeErased.rend(); ++iter2) { m_inputSequence.erase(*iter2); } }
void readIndexSetFromFile(IndexSet<Index2D> &Lambda, string filename) { std::ifstream infile (filename.c_str()); if (infile.is_open()) { cerr << " Indexset file is open." << endl; } else { cerr << " Indexset file " << filename.c_str() << " is not open." << endl; } int t1,t2; int j1,j2; long k1,k2; T coeff; while(!infile.eof()) { infile >> t1 >> j1 >> k1 >> t2 >> j2 >> k2 >> coeff; if (t1 == 1 && t2 == 1) { Index1D index_x(j1,k1,XWavelet); Index1D index_y(j2,k2,XWavelet); Lambda.insert(Index2D(index_x,index_y)); } else if (t1 == 1 && t2 == 0) { Index1D index_x(j1,k1,XWavelet); Index1D index_y(j2,k2,XBSpline); Lambda.insert(Index2D(index_x,index_y)); } else if (t1 == 0 && t2 == 1) { Index1D index_x(j1,k1,XBSpline); Index1D index_y(j2,k2,XWavelet); Lambda.insert(Index2D(index_x,index_y)); } else if (t1 == 0 && t2 == 0) { Index1D index_x(j1,k1,XBSpline); Index1D index_y(j2,k2,XBSpline); Lambda.insert(Index2D(index_x,index_y)); } else { std::cerr << "Could not read file." << std::endl; exit(1); return; } } }
// Find the IndexSet such that modDown to that set of primes makes the // additive term due to rounding into the dominant noise term void Ctxt::findBaseSet(IndexSet& s) const { if (getNoiseVar()<=0.0) { // an empty ciphertext s = context.ctxtPrimes; return; } assert(verifyPrimeSet()); bool halfSize = context.containsSmallPrime(); double curNoise = log(getNoiseVar())/2; double firstNoise = context.logOfPrime(0); double noiseThreshold = log(modSwitchAddedNoiseVar())*0.55; // FIXME: The above should have been 0.5. Making it a bit more means // that we will mod-switch a little less frequently, whether this is // a good thing needs to be tested. // remove special primes, if they are included in this->primeSet s = getPrimeSet(); if (!s.disjointFrom(context.specialPrimes)) { // scale down noise curNoise -= context.logOfProduct(context.specialPrimes); s.remove(context.specialPrimes); } /* We compare below to noiseThreshold+1 rather than to noiseThreshold * to make sure that if you mod-switch down to c.findBaseSet() and * then immediately call c.findBaseSet() again, it will not tell you * to mod-switch further down. Note that mod-switching adds close to * noiseThreshold to the scaled noise, so if the scaled noise was * equal to noiseThreshold then after mod-switchign you would have * roughly twice as much noise. Since we're mesuring the log, it means * that you may have as much as noiseThreshold+log(2), which we round * up to noiseThreshold+1 in the test below. */ if (curNoise<=noiseThreshold+1) return; // no need to mod down // if the first prime in half size, begin by removing it if (halfSize && s.contains(0)) { curNoise -= firstNoise; s.remove(0); } // while noise is larger than threshold, scale down by the next prime while (curNoise>noiseThreshold && !empty(s)) { curNoise -= context.logOfPrime(s.last()); s.remove(s.last()); } // Add 1st prime if s is empty or if this does not increase noise too much if (empty(s) || (!s.contains(0) && curNoise+firstNoise<=noiseThreshold)) { s.insert(0); curNoise += firstNoise; } if (curNoise>noiseThreshold && log_of_ratio()>-0.5) cerr << "Ctxt::findBaseSet warning: already at lowest level\n"; }
void readContextBinary(istream& str, FHEcontext& context) { assert(readEyeCatcher(str, BINIO_EYE_CONTEXT_BEGIN)==0); // Get the standard deviation context.stdev = read_raw_xdouble(str); long sizeOfS = read_raw_int(str); IndexSet s; for(long tmp, i=0; i<sizeOfS; i++){ tmp = read_raw_int(str); s.insert(tmp); } context.moduli.clear(); context.specialPrimes.clear(); context.ctxtPrimes.clear(); long nPrimes = read_raw_int(str); for (long p,i=0; i<nPrimes; i++) { p = read_raw_int(str); context.moduli.push_back(Cmodulus(context.zMStar,p,0)); if (s.contains(i)) context.specialPrimes.insert(i); // special prime else context.ctxtPrimes.insert(i); // ciphertext prime } long nDigits = read_raw_int(str); context.digits.resize(nDigits); for(long i=0; i<(long)context.digits.size(); i++){ sizeOfS = read_raw_int(str); for(long tmp, n=0; n<sizeOfS; n++){ tmp = read_raw_int(str); context.digits[i].insert(tmp); } } // Read in the partition of m into co-prime factors (if bootstrappable) Vec<long> mv; read_ntl_vec_long(str, mv); long t = read_raw_int(str); bool consFlag = read_raw_int(str); if (mv.length()>0) { context.makeBootstrappable(mv, t, consFlag); } assert(readEyeCatcher(str, BINIO_EYE_CONTEXT_END)==0); }
IndexSet<Index1D> LambdaForEigenvalues(int jmin, int jmax, const Basis1D &basis, T radius, bool with_BSplines) { const BSpline<T,Primal,R,CDF> phi = basis.mra.phi; const Wavelet<T,Primal,R,CDF> psi = basis.psi; IndexSet<Index1D> Lambda; int k_left, k_right; if (with_BSplines) { for (int j=jmin; j<=jmax; ++j) { k_left = std::floor(-pow2i<T>(j)*radius-psi.support(0,0).l2); k_right = std::ceil(pow2i<T>(j)*radius-psi.support(0,0).l1); for (int k=k_left; k<=k_right; ++k) { Lambda.insert(Index1D(j,k,XWavelet)); } } k_left = int(std::floor(-pow2i<T>(jmin)*radius-phi.support(0,0).l2)); k_right = int(std::ceil( pow2i<T>(jmin)*radius-phi.support(0,0).l1)); for (int k=k_left; k<=k_right; ++k) { Lambda.insert(Index1D(jmin,k,XBSpline)); } } else { for (int j=jmin; j<=jmax; ++j) { int k_left, k_right; if (j>=-6) { k_left = std::floor(-pow2i<T>(j)*radius-psi.support(0,0).l2); k_right = std::ceil(pow2i<T>(j)*radius-psi.support(0,0).l1); if (k_left>=0) cout << "j=" << j << ", k_left=" << k_left << endl; if (k_right<=0) cout << "j=" << j << ", k_right=" << k_right << endl; } else { k_left = -psi.d-psi.d_; k_right = psi.d+psi.d_; } for (int k=k_left; k<=k_right; ++k) { Lambda.insert(Index1D(j,k,XWavelet)); } } } return Lambda; }
//------------------------------add_liveout------------------------------------ // Add a live-out value to a given blocks live-out set. If it is new, then // also add it to the delta set and stick the block on the worklist. void PhaseLive::add_liveout( Block *p, uint r, VectorSet &first_pass ) { IndexSet *live = &_live[p->_pre_order-1]; if( live->insert(r) ) { // If actually inserted... // We extended the live-out set. See if the value is generated locally. // If it is not, then we must extend the live-in set. if( !_defs[p->_pre_order-1].member( r ) ) { if( !_deltas[p->_pre_order-1] && // Not on worklist? first_pass.test(p->_pre_order) ) _worklist->push(p); // Actually go on worklist if already 1st pass getset(p)->insert(r); } } }
//------------------------------Union------------------------------------------ // Union edges of B into A void PhaseIFG::Union( uint a, uint b ) { assert( _is_square, "only on square" ); IndexSet *A = &_adjs[a]; IndexSetIterator b_elements(&_adjs[b]); uint datum; while ((datum = b_elements.next()) != 0) { if(A->insert(datum)) { _adjs[datum].insert(a); lrgs(a).invalid_degree(); lrgs(datum).invalid_degree(); } } }
// Find the IndexSet such that modDown to that set of primes makes the // additive term due to rounding into the dominant noise term void Ctxt::findBaseSet(IndexSet& s) const { if (getNoiseVar()<=0.0) { // an empty ciphertext s = context.ctxtPrimes; return; } assert(verifyPrimeSet()); bool halfSize = context.containsSmallPrime(); double addedNoise = log(modSwitchAddedNoiseVar())/2; double curNoise = log(getNoiseVar())/2; double firstNoise = context.logOfPrime(0); // remove special primes, if they are included in this->primeSet s = getPrimeSet(); if (!s.disjointFrom(context.specialPrimes)) { // scale down noise curNoise -= context.logOfProduct(context.specialPrimes); s.remove(context.specialPrimes); } if (curNoise<=2*addedNoise) return; // no need to mod down // if the first prime in half size, begin by removing it if (halfSize && s.contains(0)) { curNoise -= firstNoise; s.remove(0); } // while noise is larger than added term, scale down by the next prime while (curNoise>addedNoise && card(s)>1) { curNoise -= context.logOfPrime(s.last()); s.remove(s.last()); } if (halfSize) { // If noise is still too big, drop last big prime and insert half-size prime if (curNoise>addedNoise) { curNoise = firstNoise; s = IndexSet(0); } // Otherwise check if you can add back the half-size prime else if (curNoise+firstNoise <= addedNoise) { curNoise += firstNoise; s.insert(0); } } if (curNoise>addedNoise && log_of_ratio()>-0.5) cerr << "Ctxt::findBaseSet warning: already at lowest level\n"; }
//------------------------------add_liveout------------------------------------ // Add a vector of live-out values to a given blocks live-out set. void PhaseLive::add_liveout( Block *p, IndexSet *lo, VectorSet &first_pass ) { IndexSet *live = &_live[p->_pre_order-1]; IndexSet *defs = &_defs[p->_pre_order-1]; IndexSet *on_worklist = _deltas[p->_pre_order-1]; IndexSet *delta = on_worklist ? on_worklist : getfreeset(); IndexSetIterator elements(lo); uint r; while ((r = elements.next()) != 0) { if( live->insert(r) && // If actually inserted... !defs->member( r ) ) // and not defined locally delta->insert(r); // Then add to live-in set } if( delta->count() ) { // If actually added things _deltas[p->_pre_order-1] = delta; // Flag as on worklist now if( !on_worklist && // Not on worklist? first_pass.test(p->_pre_order) ) _worklist->push(p); // Actually go on worklist if already 1st pass } else { // Nothing there; just free it delta->set_next(_free_IndexSet); _free_IndexSet = delta; // Drop onto free list } }
bool Octree::intersectHit( IndexSet& tris ) { if(this->children.size() > 0) return false; for(StdVector<BaseTriangle*>::iterator it = triangleData.begin(); it != triangleData.end(); it++) { BaseTriangle * face = *it; tris.insert( face->index ); } root()->selectedChildren.push_back(this); return true; }
int main (int argc, char *argv[]) { if (argc != 5 && argc != 6) { cout << "usage " << argv[0] << " d d_ max_its example [jmin]" << endl; exit(1); } T c = 1.; T contraction = 0.125; T threshTol = 0.1, cgTol = 0.1*threshTol, resTol=1e-4; int d=atoi(argv[1]), d_=atoi(argv[2]); int NumOfIterations=atoi(argv[3]); int example=atoi(argv[4]); int jmin=0; int rhs_order=10; if (argc==5) { if (d==2 && d_==2) { if (example==1) jmin=-2; else if (example==2) jmin=-4; else if (example==3) jmin=-1; else if (example==4) jmin=0; else if (example==5) jmin=0; else if (example==6) jmin=-1; //better convergence behaviour } else if (d==3 && d_==3) { if (example==1) jmin=-2; else if (example==2) jmin=-4; else if (example==3) jmin=-1; else if (example==4) jmin=0; else if (example==5) jmin=-1; else if (example==6) jmin=-1; //better convergence behaviour } else if (d==3 && d_==5) { if (example==1) jmin=-2; else if (example==2) jmin=-4; else if (example==3) jmin=-1; else if (example==4) jmin=0; else if (example==5) jmin=-1; else if (example==6) jmin=-1; //better convergence behaviour } //jmin = estimateMinimalLevel(example, c, d,d_); } else { jmin=atoi(argv[5]); } if (example==6) rhs_order=20; cout << "Initializing S-ADWAV, jmin = " << jmin << endl; Basis1D basis(d,d_,jmin); HelmholtzBilinearForm1D Bil(basis,c); Preconditioner1D P(basis); Compression1D Compr(basis); //MA A(Bil,P,Compr,0,2*8192,2*8192); MA A(Bil,P,Compr); RefSols_PDE_Realline1D<T> refsol; refsol.setExample(example, 1., 0, c); Function<T> rhs(refsol.rhs,refsol.sing_pts); RhsIntegral1D rhsintegral1d(basis, rhs, refsol.deltas, 25); Rhs F(rhsintegral1d,P); IndexSet<Index1D> InitialLambda; InitialLambda.insert(Index1D(jmin,1,XBSpline)); S_Adwav s_adwav(basis, A, F, contraction, threshTol, cgTol, resTol, NumOfIterations, 2, 1e-2); cout << "... finished." << endl; Timer time; time.start(); s_adwav.solve_cg(InitialLambda, refsol.H1norm()); time.stop(); cout << "S-ADWAV required " << time.elapsed() << " seconds real time" << endl; RhsIntegral1D rhsintegral1d_postproc(basis,rhs, refsol.deltas,60); Rhs F_postproc(rhsintegral1d_postproc,P); cout << "Postprocessing started." << endl; stringstream filename; filename << "s-adwav-realline-helmholtz1d-conv_" << example << "_" << d << "_" << d_ << "_" << jmin << ".dat"; assert(c==1); postprocessing_H1<T,Index1D, S_Adwav, MA, Rhs>(s_adwav, A, F_postproc, refsol.H1norm(), filename.str().c_str()); cout << "Postprocessing finished." << endl; stringstream plot_filename; plot_filename << "s-adwav-realline-helmholtz1d-plot_" << example << "_" << d << "_" << d_ << "_" << jmin << ".dat"; cout << "Plot of solution started." << endl; plot<T, Basis1D, Preconditioner1D>(basis, s_adwav.solutions[NumOfIterations-1], P, refsol.u, refsol.d_u, -10., 10., pow2i<T>(-5), plot_filename.str().c_str()); cout << "Plot of solution finished." << endl; return 0; }
// union IndexSet operator|(const IndexSet& s, const IndexSet& t) { IndexSet r = s; r.insert(t); return r; }
//----------------------------------------------------------------------------- void RegularCutRefinement::compute_markers(std::vector<int>& refinement_markers, IndexSet& marked_edges, const Mesh& mesh, const MeshFunction<bool>& cell_markers) { // Topological dimension const std::size_t D = mesh.topology().dim(); // Create edge markers and initialize to false const std::size_t edges_per_cell = D + 1; std::vector<std::vector<bool> > edge_markers(mesh.num_cells()); for (std::size_t i = 0; i < mesh.num_cells(); i++) { edge_markers[i].resize(edges_per_cell); for (std::size_t j = 0; j < edges_per_cell; j++) edge_markers[i][j] = false; } // Create index sets for marked cells IndexSet cells(mesh.num_cells()); IndexSet marked_cells(mesh.num_cells()); // Get bisection data const std::vector<std::size_t>* bisection_twins = NULL; if (mesh.data().exists("bisection_twins", D)) bisection_twins = &(mesh.data().array("bisection_twins", D)); // Iterate until no more cells are marked cells.fill(); while (!cells.empty()) { // Iterate over all cells in list for (std::size_t _i = 0; _i < cells.size(); _i++) { // Get cell index and create cell const std::size_t cell_index = cells[_i]; const Cell cell(mesh, cell_index); // Count the number of marked edges const std::size_t num_marked = count_markers(edge_markers[cell_index]); // Check whether cell has a bisection twin std::size_t bisection_twin = cell_index; bool is_bisected = false; if (bisection_twins) { bisection_twin = (*bisection_twins)[cell_index]; is_bisected = bisection_twin != cell_index; } // Get bisection edge std::size_t common_edge = 0; std::size_t bisection_edge = 0; if (is_bisected) { common_edge = find_common_edges(cell, mesh, bisection_twin).first; bisection_edge = find_bisection_edges(cell, mesh, bisection_twin).first; } // Decide if cell should be refined bool refine = false; refine = refine || cell_markers[cell_index]; if (is_bisected) refine = refine || num_marked > 0; else { refine = refine || num_marked > 1; refine = refine || too_thin(cell, edge_markers[cell_index]); } // Skip cell if it should not be marked if (!refine) continue; // Iterate over edges for (EdgeIterator edge(cell); !edge.end(); ++edge) { // Skip edge if it is a bisected edge of a bisected cell if (is_bisected && edge.pos() == bisection_edge) continue; // Mark edge in current cell if (!edge_markers[cell_index][edge.pos()]) { edge_markers[cell_index][edge.pos()] = true; marked_cells.insert(cell_index); } // Insert edge into set of marked edges but only if the edge // is not the common edge of a bisected cell in which case it // will later be removed and no new vertex be inserted... if (!is_bisected || edge.pos() != common_edge) marked_edges.insert(edge->index()); // Iterate over cells sharing edge for (CellIterator neighbor(*edge); !neighbor.end(); ++neighbor) { // Get local edge number of edge relative to neighbor const std::size_t local_index = neighbor->index(*edge); // Mark edge for refinement if (!edge_markers[neighbor->index()][local_index]) { edge_markers[neighbor->index()][local_index] = true; marked_cells.insert(neighbor->index()); } } } } // Copy marked cells cells = marked_cells; marked_cells.clear(); } // Extract which cells to refine and indices which edges to bisect refinement_markers.resize(mesh.num_cells()); for (std::size_t i = 0; i < edge_markers.size(); i++) { // Count the number of marked edges const std::size_t num_marked = count_markers(edge_markers[i]); // Check if cell has been bisected before const bool is_bisected = bisection_twins && (*bisection_twins)[i] != i; // No refinement if (num_marked == 0) refinement_markers[i] = no_refinement; // Mark for bisection else if (num_marked == 1 && !is_bisected) refinement_markers[i] = extract_edge(edge_markers[i]); // Mark for regular refinement else if (num_marked == edges_per_cell && !is_bisected) refinement_markers[i] = regular_refinement; // Mark for bisection backtracking else if (num_marked == 2 && is_bisected) refinement_markers[i] = backtrack_bisection; // Mark for bisection backtracking and refinement else if (num_marked == edges_per_cell && is_bisected) refinement_markers[i] = backtrack_bisection_refine; // Sanity check else dolfin_error("RegularCutRefinement.cpp", "compute marked edges", "Unexpected number of edges marked"); } }
void TopologyGraph::createBoundary(unsigned graphNum, TopologyGraph::IndexVector& output) const { // nothing to do - bail if (_verts.empty() || graphNum+1 > _maxGraphID) return; // graph ID is one more than the graph number passed in: unsigned graphID = graphNum + 1u; // Find the starting point (vertex with minimum Y) for this graph ID. // By the nature of disconnected graphs, that start point is all we need // to ensure we are walking a single connected mesh. Index vstart = _verts.end(); for (VertexSet::const_iterator vert = _verts.begin(); vert != _verts.end(); ++vert) { if (vert->_graphID == graphID) { if (vstart == _verts.end() || vert->y() < vstart->y()) { vstart = vert; } } } // couldn't find a start point - bail (should never happen) if (vstart == _verts.end()) return; // starting with the minimum-Y vertex (which is guaranteed to be in the boundary) // traverse the outside of the point set. Do this by sorting all the edges by // their angle relative to the vector from the previous point. The "leftest" turn // represents the edge connecting the current point to the next boundary point. // Thusly we walk the boundary counterclockwise until we return to the start point. Index vptr = vstart; Index vptr_prev = _verts.end(); IndexSet visited; while( true ) { // store this vertex in the result set: output.push_back( vptr ); // pull up the next 2D vertex (XY plane): osg::Vec2d vert ( vptr->x(), vptr->y() ); // construct the "base" vector that points from the previous // point to the current point; or to +X in the initial case osg::Vec2d base; if ( vptr_prev == _verts.end() ) { base.set(1, 0); } else { base = vert - osg::Vec2d( vptr_prev->x(), vptr_prev->y() ); base.normalize(); } // pull up the edge set for this vertex: EdgeMap::const_iterator ei = _edgeMap.find(vptr); if (ei == _edgeMap.end()) continue; // should be impossible const IndexSet& edges = ei->second; // find the edge with the minimum delta angle to the base vector double bestScore = -DBL_MAX; Index bestEdge = _verts.end(); //OE_NOTICE << "VERTEX (" << // vptr->x() << ", " << vptr->y() << ", " // << ") has " << edges.size() << " edges..." // << std::endl; unsigned possibleEdges = 0u; for( IndexSet::iterator e = edges.begin(); e != edges.end(); ++e ) { // don't go back from whence we just came if ( *e == vptr_prev ) continue; // never return to a vert we've already visited if ( visited.find(*e) != visited.end() ) continue; ++possibleEdges; // calculate the angle between the base vector and the current edge: osg::Vec2d edgeVert( (*e)->x(), (*e)->y() ); osg::Vec2d edge = edgeVert - vert; edge.normalize(); double cross = base.x()*edge.y() - base.y()*edge.x(); double dot = base * edge; double score; if (cross <= 0.0) score = 1.0-dot; // [0..2] else score = dot-1.0; // [-2..0] //OE_NOTICE << " check: " << (*e)->x() << ", " << (*e)->y() << std::endl; //OE_NOTICE << " base = " << base.x() << ", " << base.y() << std::endl; //OE_NOTICE << " edge = " << edge.x() << ", " << edge.y() << std::endl; //OE_NOTICE << " crs = " << cross << ", dot = " << dot << ", score = " << score << std::endl; if (score > bestScore) { bestScore = score; bestEdge = *e; } } if ( bestEdge == _verts.end() ) { // this should never happen // but sometimes does anyway OE_WARN << LC << getName() << " - Illegal state - reached a dead end during boundary detection. Vertex (" << vptr->x() << ", " << vptr->y() << ") has " << possibleEdges << " possible edges.\n" << std::endl; break; } // store the previous: vptr_prev = vptr; // follow the chosen edge around the outside of the geometry: //OE_DEBUG << " BEST SCORE = " << bestScore << std::endl; vptr = bestEdge; // record this vert so we don't visit it again. visited.insert( vptr ); // once we make it all the way around, we're done: if ( vptr == vstart ) break; } }
//------------------------------build_ifg_virtual------------------------------ // Actually build the interference graph. Uses virtual registers only, no // physical register masks. This allows me to be very aggressive when // coalescing copies. Some of this aggressiveness will have to be undone // later, but I'd rather get all the copies I can now (since unremoved copies // at this point can end up in bad places). Copies I re-insert later I have // more opportunity to insert them in low-frequency locations. void PhaseChaitin::build_ifg_virtual( ) { // For all blocks (in any order) do... for( uint i=0; i<_cfg._num_blocks; i++ ) { Block *b = _cfg._blocks[i]; IndexSet *liveout = _live->live(b); // The IFG is built by a single reverse pass over each basic block. // Starting with the known live-out set, we remove things that get // defined and add things that become live (essentially executing one // pass of a standard LIVE analysis). Just before a Node defines a value // (and removes it from the live-ness set) that value is certainly live. // The defined value interferes with everything currently live. The // value is then removed from the live-ness set and it's inputs are // added to the live-ness set. for( uint j = b->end_idx() + 1; j > 1; j-- ) { Node *n = b->_nodes[j-1]; // Get value being defined uint r = n2lidx(n); // Some special values do not allocate if( r ) { // Remove from live-out set liveout->remove(r); // Copies do not define a new value and so do not interfere. // Remove the copies source from the liveout set before interfering. uint idx = n->is_Copy(); if( idx ) liveout->remove( n2lidx(n->in(idx)) ); // Interfere with everything live interfere_with_live( r, liveout ); } // Make all inputs live if( !n->is_Phi() ) { // Phi function uses come from prior block for( uint k = 1; k < n->req(); k++ ) liveout->insert( n2lidx(n->in(k)) ); } // 2-address instructions always have the defined value live // on entry to the instruction, even though it is being defined // by the instruction. We pretend a virtual copy sits just prior // to the instruction and kills the src-def'd register. // In other words, for 2-address instructions the defined value // interferes with all inputs. uint idx; if( n->is_Mach() && (idx = n->as_Mach()->two_adr()) ) { const MachNode *mach = n->as_Mach(); // Sometimes my 2-address ADDs are commuted in a bad way. // We generally want the USE-DEF register to refer to the // loop-varying quantity, to avoid a copy. uint op = mach->ideal_Opcode(); // Check that mach->num_opnds() == 3 to ensure instruction is // not subsuming constants, effectively excludes addI_cin_imm // Can NOT swap for instructions like addI_cin_imm since it // is adding zero to yhi + carry and the second ideal-input // points to the result of adding low-halves. // Checking req() and num_opnds() does NOT distinguish addI_cout from addI_cout_imm if( (op == Op_AddI && mach->req() == 3 && mach->num_opnds() == 3) && n->in(1)->bottom_type()->base() == Type::Int && // See if the ADD is involved in a tight data loop the wrong way n->in(2)->is_Phi() && n->in(2)->in(2) == n ) { Node *tmp = n->in(1); n->set_req( 1, n->in(2) ); n->set_req( 2, tmp ); } // Defined value interferes with all inputs uint lidx = n2lidx(n->in(idx)); for( uint k = 1; k < n->req(); k++ ) { uint kidx = n2lidx(n->in(k)); if( kidx != lidx ) _ifg->add_edge( r, kidx ); } } } // End of forall instructions in block } // End of forall blocks }
void buildModChain(FHEcontext &context, long nLevels, long nDgts) { #ifdef NO_HALF_SIZE_PRIME long nPrimes = nLevels; #else long nPrimes = (nLevels+1)/2; // The first prime should be of half the size. The code below tries to find // a prime q0 of this size where q0-1 is divisible by 2^k * m for some k>1. // Then if the plaintext space is a power of two it tries to choose the // second prime q1 so that q0*q1 = 1 mod ptxtSpace. All the other primes are // chosen so that qi-1 is divisible by 2^k * m for as large k as possible. long twoM; if (ALT_CRT) twoM = 2; else twoM = 2 * context.zMStar.getM(); long bound = (1L << (context.bitsPerLevel-1)); while (twoM < bound/(2*context.bitsPerLevel)) twoM *= 2; // divisible by 2^k * m for a larger k bound = bound - (bound % twoM) +1; // = 1 mod 2m long q0 = context.AddPrime(bound, twoM, false, !ALT_CRT); // add next prime to chain assert(q0 != 0); nPrimes--; #endif // Choose the next primes as large as possible if (nPrimes>0) AddPrimesByNumber(context, nPrimes); // calculate the size of the digits if (nDgts > nPrimes) nDgts = nPrimes; // sanity checks if (nDgts <= 0) nDgts = 1; context.digits.resize(nDgts); // allocate space IndexSet s1; double sizeSoFar = 0.0; double maxDigitSize = 0.0; if (nDgts>1) { // we break ciphetext into a few digits when key-switching double dsize = context.logOfProduct(context.ctxtPrimes)/nDgts; // estimate double target = dsize-(context.bitsPerLevel/3.0); long idx = context.ctxtPrimes.first(); for (long i=0; i<nDgts-1; i++) { // compute next digit IndexSet s; while (idx <= context.ctxtPrimes.last() && (empty(s)||sizeSoFar<target)) { s.insert(idx); sizeSoFar += log((double)context.ithPrime(idx)); idx = context.ctxtPrimes.next(idx); } assert (!empty(s)); context.digits[i] = s; s1.insert(s); double thisDigitSize = context.logOfProduct(s); if (maxDigitSize < thisDigitSize) maxDigitSize = thisDigitSize; target += dsize; } IndexSet s = context.ctxtPrimes / s1; // all the remaining primes if (!empty(s)) { context.digits[nDgts-1] = s; double thisDigitSize = context.logOfProduct(s); if (maxDigitSize < thisDigitSize) maxDigitSize = thisDigitSize; } else { // If last digit is empty, remove it nDgts--; context.digits.resize(nDgts); } } else { maxDigitSize = context.logOfProduct(context.ctxtPrimes); context.digits[0] = context.ctxtPrimes; } // Add primes to the chain for the P factor of key-switching long p2r = (context.rcData.alMod)? context.rcData.alMod->getPPowR() : context.alMod.getPPowR(); double sizeOfSpecialPrimes = maxDigitSize + log(nDgts/32.0)/2 + log(context.stdev *2) + log((double)p2r); AddPrimesBySize(context, sizeOfSpecialPrimes, true); }
void PhaseLive::compute(uint maxlrg) { _maxlrg = maxlrg; _worklist = new (_arena) Block_List(); // Init the sparse live arrays. This data is live on exit from here! // The _live info is the live-out info. _live = (IndexSet*)_arena->Amalloc(sizeof(IndexSet)*_cfg._num_blocks); uint i; for( i=0; i<_cfg._num_blocks; i++ ) { _live[i].initialize(_maxlrg); } // Init the sparse arrays for delta-sets. ResourceMark rm; // Nuke temp storage on exit // Does the memory used by _defs and _deltas get reclaimed? Does it matter? TT // Array of values defined locally in blocks _defs = NEW_RESOURCE_ARRAY(IndexSet,_cfg._num_blocks); for( i=0; i<_cfg._num_blocks; i++ ) { _defs[i].initialize(_maxlrg); } // Array of delta-set pointers, indexed by block pre_order-1. _deltas = NEW_RESOURCE_ARRAY(IndexSet*,_cfg._num_blocks); memset( _deltas, 0, sizeof(IndexSet*)* _cfg._num_blocks); _free_IndexSet = NULL; // Blocks having done pass-1 VectorSet first_pass(Thread::current()->resource_area()); // Outer loop: must compute local live-in sets and push into predecessors. uint iters = _cfg._num_blocks; // stat counters for( uint j=_cfg._num_blocks; j>0; j-- ) { Block *b = _cfg._blocks[j-1]; // Compute the local live-in set. Start with any new live-out bits. IndexSet *use = getset( b ); IndexSet *def = &_defs[b->_pre_order-1]; uint i; for( i=b->_nodes.size(); i>1; i-- ) { Node *n = b->_nodes[i-1]; if( n->is_Phi() ) break; // BoxNodes keep their input alive as long as their uses. If we // see a BoxNode then make its input live to the Root block. // Because we are solving LIVEness, the input now becomes live // over the whole procedure, interferencing with everything else // and getting a private unshared stack slot. YeeeHaw! MachNode *mach = n->is_Mach(); if( mach && mach->ideal_Opcode() == Op_Box ) getset(_cfg._broot)->insert( _names[n->in(1)->_idx] ); uint r = _names[n->_idx]; def->insert( r ); use->remove( r ); uint cnt = n->req(); for( uint k=1; k<cnt; k++ ) { Node *nk = n->in(k); uint nkidx = nk->_idx; if( _cfg._bbs[nkidx] != b ) use->insert( _names[nkidx] ); } } // Remove anything defined by Phis and the block start instruction for( uint k=i; k>0; k-- ) { uint r = _names[b->_nodes[k-1]->_idx]; def->insert( r ); use->remove( r ); } // Push these live-in things to predecessors for( uint l=1; l<b->num_preds(); l++ ) { Block *p = _cfg._bbs[b->pred(l)->_idx]; add_liveout( p, use, first_pass ); // PhiNode uses go in the live-out set of prior blocks. for( uint k=i; k>0; k-- ) add_liveout( p, _names[b->_nodes[k-1]->in(l)->_idx], first_pass ); } freeset( b ); first_pass.set(b->_pre_order); // Inner loop: blocks that picked up new live-out values to be propagated while( _worklist->size() ) { // !!!!! // #ifdef ASSERT iters++; // #endif Block *b = _worklist->pop(); IndexSet *delta = getset(b); assert( delta->count(), "missing delta set" ); // Add new-live-in to predecessors live-out sets for( uint l=1; l<b->num_preds(); l++ ) add_liveout( _cfg._bbs[b->pred(l)->_idx], delta, first_pass ); freeset(b); } // End of while-worklist-not-empty } // End of for-all-blocks-outer-loop // We explicitly clear all of the IndexSets which we are about to release. // This allows us to recycle their internal memory into IndexSet's free list. for( i=0; i<_cfg._num_blocks; i++ ) { _defs[i].clear(); if (_deltas[i]) { // Is this always true? _deltas[i]->clear(); } } IndexSet *free = _free_IndexSet; while (free != NULL) { IndexSet *temp = free; free = free->next(); temp->clear(); } }
int main(int argc, char *argv[]) { if (argc<2) { cout << "\nUsage: " << argv[0] << " L [c=2 w=64 k=80 d=1]" << endl; cout << " L is the number of levels\n"; cout << " optional c is number of columns in the key-switching matrices (default=2)\n"; cout << " optional w is Hamming weight of the secret key (default=64)\n"; cout << " optional k is the security parameter (default=80)\n"; cout << " optional d specifies GF(2^d) arithmetic (default=1, must be <=16)\n"; // cout << " k is the security parameter\n"; // cout << " m determines the ring mod Phi_m(X)" << endl; cout << endl; exit(0); } cout.unsetf(ios::floatfield); cout.precision(4); long L = atoi(argv[1]); long c = 2; long w = 64; long k = 80; long d = 1; if (argc>2) c = atoi(argv[2]); if (argc>3) w = atoi(argv[3]); if (argc>4) k = atoi(argv[4]); if (argc>5) d = atoi(argv[5]); if (d>16) Error("d cannot be larger than 16\n"); cout << "\nTesting FHE with parameters L="<<L << ", c="<<c<<", w="<<w<<", k="<<k<<", d="<<d<< endl; // get a lower-bound on the parameter N=phi(m): // 1. Empirically, we use ~20-bit small primes in the modulus chain (the main // constraints is that 2m must divide p-1 for every prime p). The first // prime is larger, a 40-bit prime. (If this is a 32-bit machine then we // use two 20-bit primes instead.) // 2. With L levels, the largest modulus for "fresh ciphertexts" has size // q0 ~ p0 * p^{L} ~ 2^{40+20L} // 3. We break each ciphertext into upto c digits, do each digit is as large // as D=2^{(40+20L)/c} // 4. The added noise variance term from the key-switching operation is // c*N*sigma^2*D^2, and this must be mod-switched down to w*N (so it is // on part with the added noise from modulus-switching). Hence the ratio // P that we use for mod-switching must satisfy c*N*sigma^2*D^2/P^2<w*N, // or P > sqrt(c/w) * sigma * 2^{(40+20L)/c} // 5. With this extra P factor, the key-switching matrices are defined // relative to a modulus of size // Q0 = q0*P ~ sqrt{c/w} sigma 2^{(40+20L)(1+1/c)} // 6. To get k-bit security we need N>log(Q0/sigma)(k+110)/7.2, i.e. roughly // N > (40+20L)(1+1/c)(k+110) / 7.2 long ptxtSpace = 2; double cc = 1.0+(1.0/(double)c); long N = (long) ceil((pSize*L+p0Size)*cc*(k+110)/7.2); cout << " bounding phi(m) > " << N << endl; #if 0 // A small m for debugging purposes long m = 15; #else // pre-computed values of [phi(m),m,d] long ms[][4] = { //phi(m) m ord(2) c_m*1000 { 1176, 1247, 28, 3736}, { 1936, 2047, 11, 3870}, { 2880, 3133, 24, 3254}, { 4096, 4369, 16, 3422}, { 5292, 5461, 14, 4160}, { 5760, 8435, 24, 8935}, { 8190, 8191, 13, 1273}, {10584, 16383, 14, 8358}, {10752, 11441, 48, 3607}, {12000, 13981, 20, 2467}, {11520, 15665, 24, 14916}, {14112, 18415, 28, 11278}, {15004, 15709, 22, 3867}, {15360, 20485, 24, 12767}, // {16384, 21845, 16, 12798}, {17208 ,21931, 24, 18387}, {18000, 18631, 25, 4208}, {18816, 24295, 28, 16360}, {19200, 21607, 40, 35633}, {21168, 27305, 28, 15407}, {23040, 23377, 48, 5292}, {24576, 24929, 48, 5612}, {27000, 32767, 15, 20021}, {31104, 31609, 71, 5149}, {42336, 42799, 21, 5952}, {46080, 53261, 24, 33409}, {49140, 57337, 39, 2608}, {51840, 59527, 72, 21128}, {61680, 61681, 40, 1273}, {65536, 65537, 32, 1273}, {75264, 82603, 56, 36484}, {84672, 92837, 56, 38520} }; #if 0 for (long i = 0; i < 25; i++) { long m = ms[i][1]; PAlgebra alg(m); alg.printout(); cout << "\n"; // compute phi(m) directly long phim = 0; for (long j = 0; j < m; j++) if (GCD(j, m) == 1) phim++; if (phim != alg.phiM()) cout << "ERROR\n"; } exit(0); #endif // find the first m satisfying phi(m)>=N and d | ord(2) in Z_m^* long m = 0; for (unsigned i=0; i<sizeof(ms)/sizeof(long[3]); i++) if (ms[i][0]>=N && (ms[i][2] % d) == 0) { m = ms[i][1]; c_m = 0.001 * (double) ms[i][3]; break; } if (m==0) Error("Cannot support this L,d combination"); #endif // m = 257; FHEcontext context(m); #if 0 context.stdev = to_xdouble(0.5); // very low error #endif activeContext = &context; // Mark this as the "current" context context.zMstar.printout(); cout << endl; // Set the modulus chain #if 1 // The first 1-2 primes of total p0size bits #if (NTL_SP_NBITS > p0Size) AddPrimesByNumber(context, 1, 1UL<<p0Size); // add a single prime #else AddPrimesByNumber(context, 2, 1UL<<(p0Size/2)); // add two primes #endif #endif // The next L primes, as small as possible AddPrimesByNumber(context, L); ZZ productOfCtxtPrimes = context.productOfPrimes(context.ctxtPrimes); double productSize = context.logOfProduct(context.ctxtPrimes); // might as well test that the answer is roughly correct cout << " context.logOfProduct(...)-log(context.productOfPrimes(...)) = " << productSize-log(productOfCtxtPrimes) << endl; // calculate the size of the digits context.digits.resize(c); IndexSet s1; #if 0 for (long i=0; i<c-1; i++) context.digits[i] = IndexSet(i,i); context.digits[c-1] = context.ctxtPrimes / IndexSet(0,c-2); AddPrimesByNumber(context, 2, 1, true); #else double sizeSoFar = 0.0; double maxDigitSize = 0.0; if (c>1) { // break ciphetext into a few digits double dsize = productSize/c; // initial estimate double target = dsize-(pSize/3.0); long idx = context.ctxtPrimes.first(); for (long i=0; i<c-1; i++) { // compute next digit IndexSet s; while (idx <= context.ctxtPrimes.last() && sizeSoFar < target) { s.insert(idx); sizeSoFar += log((double)context.ithPrime(idx)); idx = context.ctxtPrimes.next(idx); } context.digits[i] = s; s1.insert(s); double thisDigitSize = context.logOfProduct(s); if (maxDigitSize < thisDigitSize) maxDigitSize = thisDigitSize; cout << " digit #"<<i+1<< " " <<s << ": size " << thisDigitSize << endl; target += dsize; } IndexSet s = context.ctxtPrimes / s1; // all the remaining primes context.digits[c-1] = s; double thisDigitSize = context.logOfProduct(s); if (maxDigitSize < thisDigitSize) maxDigitSize = thisDigitSize; cout << " digit #"<<c<< " " <<s << ": size " << thisDigitSize << endl; } else { maxDigitSize = context.logOfProduct(context.ctxtPrimes); context.digits[0] = context.ctxtPrimes; } // Add primes to the chain for the P factor of key-switching double sizeOfSpecialPrimes = maxDigitSize + log(c/(double)w)/2 + log(context.stdev *2); AddPrimesBySize(context, sizeOfSpecialPrimes, true); #endif cout << "* ctxtPrimes: " << context.ctxtPrimes << ", log(q0)=" << context.logOfProduct(context.ctxtPrimes) << endl; cout << "* specialPrimes: " << context.specialPrimes << ", log(P)=" << context.logOfProduct(context.specialPrimes) << endl; for (long i=0; i<context.numPrimes(); i++) { cout << " modulus #" << i << " " << context.ithPrime(i) << endl; } cout << endl; setTimersOn(); const ZZX& PhimX = context.zMstar.PhimX(); // The polynomial Phi_m(X) long phim = context.zMstar.phiM(); // The integer phi(m) FHESecKey secretKey(context); const FHEPubKey& publicKey = secretKey; #if 0 // Debug mode: use sk=1,2 DoubleCRT newSk(to_ZZX(2), context); long id1 = secretKey.ImportSecKey(newSk, 64, ptxtSpace); newSk -= 1; long id2 = secretKey.ImportSecKey(newSk, 64, ptxtSpace); #else long id1 = secretKey.GenSecKey(w,ptxtSpace); // A Hamming-weight-w secret key long id2 = secretKey.GenSecKey(w,ptxtSpace); // A second Hamming-weight-w secret key #endif ZZX zero = to_ZZX(0); // Ctxt zeroCtxt(publicKey); /******************************************************************/ /** TESTS BEGIN HERE ***/ /******************************************************************/ cout << "ptxtSpace = " << ptxtSpace << endl; GF2X G; // G is the AES polynomial, G(X)= X^8 +X^4 +X^3 +X +1 SetCoeff(G,8); SetCoeff(G,4); SetCoeff(G,3); SetCoeff(G,1); SetCoeff(G,0); GF2X X; SetX(X); #if 1 // code for rotations... { GF2X::HexOutput = 1; const PAlgebra& al = context.zMstar; const PAlgebraModTwo& al2 = context.modTwo; long ngens = al.numOfGens(); long nslots = al.NSlots(); DoubleCRT tmp(context); vector< vector< DoubleCRT > > maskTable; maskTable.resize(ngens); for (long i = 0; i < ngens; i++) { if (i==0 && al.SameOrd(i)) continue; long ord = al.OrderOf(i); maskTable[i].resize(ord+1, tmp); for (long j = 0; j <= ord; j++) { // initialize the mask that is 1 whenever // the ith coordinate is at least j vector<GF2X> maps, alphas, betas; al2.mapToSlots(maps, G); // Change G to X to get bits in the slots alphas.resize(nslots); for (long k = 0; k < nslots; k++) if (coordinate(al, i, k) >= j) alphas[k] = 1; else alphas[k] = 0; GF2X ptxt; al2.embedInSlots(ptxt, alphas, maps); // Sanity-check, make sure that encode/decode works as expected al2.decodePlaintext(betas, ptxt, G, maps); for (long k = 0; k < nslots; k++) { if (alphas[k] != betas[k]) { cout << " Mask computation failed, i="<<i<<", j="<<j<<"\n"; return 0; } } maskTable[i][j] = to_ZZX(ptxt); } } vector<GF2X> maps; al2.mapToSlots(maps, G); vector<GF2X> alphas(nslots); for (long i=0; i < nslots; i++) random(alphas[i], 8); // random degree-7 polynomial mod 2 for (long amt = 0; amt < 20; amt++) { cout << "."; GF2X ptxt; al2.embedInSlots(ptxt, alphas, maps); DoubleCRT pp(context); pp = to_ZZX(ptxt); rotate(pp, amt, maskTable); GF2X ptxt1 = to_GF2X(to_ZZX(pp)); vector<GF2X> betas; al2.decodePlaintext(betas, ptxt1, G, maps); for (long i = 0; i < nslots; i++) { if (alphas[i] != betas[(i+amt)%nslots]) { cout << " amt="<<amt<<" oops\n"; return 0; } } } cout << "\n"; #if 0 long ord0 = al.OrderOf(0); for (long i = 0; i < nslots; i++) { cout << alphas[i] << " "; if ((i+1) % (nslots/ord0) == 0) cout << "\n"; } cout << "\n\n"; cout << betas.size() << "\n"; for (long i = 0; i < nslots; i++) { cout << betas[i] << " "; if ((i+1) % (nslots/ord0) == 0) cout << "\n"; } #endif return 0; } #endif // an initial sanity check on noise estimates, // comparing the estimated variance to the actual average cout << "pk:"; checkCiphertext(publicKey.pubEncrKey, zero, secretKey); ZZX ptxt[6]; // first four are plaintext, last two are constants std::vector<Ctxt> ctxt(4, Ctxt(publicKey)); // Initialize the plaintext and constants to random 0-1 polynomials for (size_t j=0; j<6; j++) { ptxt[j].rep.SetLength(phim); for (long i = 0; i < phim; i++) ptxt[j].rep[i] = RandomBnd(ptxtSpace); ptxt[j].normalize(); if (j<4) { publicKey.Encrypt(ctxt[j], ptxt[j], ptxtSpace); cout << "c"<<j<<":"; checkCiphertext(ctxt[j], ptxt[j], secretKey); } } // perform upto 2L levels of computation, each level computing: // 1. c0 += c1 // 2. c1 *= c2 // L1' = max(L1,L2)+1 // 3. c1.reLinearlize // 4. c2 *= p4 // 5. c2.automorph(k) // k is the first generator of Zm^* /(2) // 6. c2.reLinearlize // 7. c3 += p5 // 8. c3 *= c0 // L3' = max(L3,L0,L1)+1 // 9. c2 *= c3 // L2' = max(L2,L0+1,L1+1,L3+1)+1 // 10. c0 *= c0 // L0' = max(L0,L1)+1 // 11. c0.reLinearlize // 12. c2.reLinearlize // 13. c3.reLinearlize // // The levels of the four ciphertexts behave as follows: // 0, 0, 0, 0 => 1, 1, 2, 1 => 2, 3, 3, 2 // => 4, 4, 5, 4 => 5, 6, 6, 5 // => 7, 7, 8, 7 => 8,,9, 9, 10 => [...] // // We perform the same operations on the plaintext, and after each operation // we check that decryption still works, and print the curretn modulus and // noise estimate. We stop when we get the first decryption error, or when // we reach 2L levels (which really should not happen). zz_pContext zzpc; zz_p::init(ptxtSpace); zzpc.save(); const zz_pXModulus F = to_zz_pX(PhimX); long g = context.zMstar.ZmStarGen(0); // the first generator in Zm* zz_pX x2g(g, 1); zz_pX p2; // generate a key-switching matrix from s(X^g) to s(X) secretKey.GenKeySWmatrix(/*powerOfS= */ 1, /*powerOfX= */ g, 0, 0, /*ptxtSpace=*/ ptxtSpace); // generate a key-switching matrix from s^2 to s secretKey.GenKeySWmatrix(/*powerOfS= */ 2, /*powerOfX= */ 1, 0, 0, /*ptxtSpace=*/ ptxtSpace); // generate a key-switching matrix from s^3 to s secretKey.GenKeySWmatrix(/*powerOfS= */ 3, /*powerOfX= */ 1, 0, 0, /*ptxtSpace=*/ ptxtSpace); for (long lvl=0; lvl<2*L; lvl++) { cout << "=======================================================\n"; ctxt[0] += ctxt[1]; ptxt[0] += ptxt[1]; PolyRed(ptxt[0], ptxtSpace, true); cout << "c0+=c1: "; checkCiphertext(ctxt[0], ptxt[0], secretKey); ctxt[1].multiplyBy(ctxt[2]); ptxt[1] = (ptxt[1] * ptxt[2]) % PhimX; PolyRed(ptxt[1], ptxtSpace, true); cout << "c1*=c2: "; checkCiphertext(ctxt[1], ptxt[1], secretKey); ctxt[2].multByConstant(ptxt[4]); ptxt[2] = (ptxt[2] * ptxt[4]) % PhimX; PolyRed(ptxt[2], ptxtSpace, true); cout << "c2*=p4: "; checkCiphertext(ctxt[2], ptxt[2], secretKey); ctxt[2] >>= g; zzpc.restore(); p2 = to_zz_pX(ptxt[2]); CompMod(p2, p2, x2g, F); ptxt[2] = to_ZZX(p2); cout << "c2>>="<<g<<":"; checkCiphertext(ctxt[2], ptxt[2], secretKey); ctxt[2].reLinearize(); cout << "c2.relin:"; checkCiphertext(ctxt[2], ptxt[2], secretKey); ctxt[3].addConstant(ptxt[5]); ptxt[3] += ptxt[5]; PolyRed(ptxt[3], ptxtSpace, true); cout << "c3+=p5: "; checkCiphertext(ctxt[3], ptxt[3], secretKey); ctxt[3].multiplyBy(ctxt[0]); ptxt[3] = (ptxt[3] * ptxt[0]) % PhimX; PolyRed(ptxt[3], ptxtSpace, true); cout << "c3*=c0: "; checkCiphertext(ctxt[3], ptxt[3], secretKey); ctxt[0].square(); ptxt[0] = (ptxt[0] * ptxt[0]) % PhimX; PolyRed(ptxt[0], ptxtSpace, true); cout << "c0*=c0: "; checkCiphertext(ctxt[0], ptxt[0], secretKey); ctxt[2].multiplyBy(ctxt[3]); ptxt[2] = (ptxt[2] * ptxt[3]) % PhimX; PolyRed(ptxt[2], ptxtSpace, true); cout << "c2*=c3: "; checkCiphertext(ctxt[2], ptxt[2], secretKey); } /******************************************************************/ /** TESTS END HERE ***/ /******************************************************************/ cout << endl; return 0; }
//------------------------------insert_copies---------------------------------- void PhaseAggressiveCoalesce::insert_copies( Matcher &matcher ) { // We do LRGs compressing and fix a liveout data only here since the other // place in Split() is guarded by the assert which we never hit. _phc.compress_uf_map_for_nodes(); // Fix block's liveout data for compressed live ranges. for(uint lrg = 1; lrg < _phc._maxlrg; lrg++ ) { uint compressed_lrg = _phc.Find(lrg); if( lrg != compressed_lrg ) { for( uint bidx = 0; bidx < _phc._cfg._num_blocks; bidx++ ) { IndexSet *liveout = _phc._live->live(_phc._cfg._blocks[bidx]); if( liveout->member(lrg) ) { liveout->remove(lrg); liveout->insert(compressed_lrg); } } } } // All new nodes added are actual copies to replace virtual copies. // Nodes with index less than '_unique' are original, non-virtual Nodes. _unique = C->unique(); for( uint i=0; i<_phc._cfg._num_blocks; i++ ) { Block *b = _phc._cfg._blocks[i]; uint cnt = b->num_preds(); // Number of inputs to the Phi for( uint l = 1; l<b->_nodes.size(); l++ ) { Node *n = b->_nodes[l]; // Do not use removed-copies, use copied value instead uint ncnt = n->req(); for( uint k = 1; k<ncnt; k++ ) { Node *copy = n->in(k); uint cidx = copy->is_Copy(); if( cidx ) { Node *def = copy->in(cidx); if( _phc.Find(copy) == _phc.Find(def) ) n->set_req(k,def); } } // Remove any explicit copies that get coalesced. uint cidx = n->is_Copy(); if( cidx ) { Node *def = n->in(cidx); if( _phc.Find(n) == _phc.Find(def) ) { n->replace_by(def); n->set_req(cidx,NULL); b->_nodes.remove(l); l--; continue; } } if( n->is_Phi() ) { // Get the chosen name for the Phi uint phi_name = _phc.Find( n ); // Ignore the pre-allocated specials if( !phi_name ) continue; // Check for mismatch inputs to Phi for( uint j = 1; j<cnt; j++ ) { Node *m = n->in(j); uint src_name = _phc.Find(m); if( src_name != phi_name ) { Block *pred = _phc._cfg._bbs[b->pred(j)->_idx]; Node *copy; assert(!m->is_Con() || m->is_Mach(), "all Con must be Mach"); // Rematerialize constants instead of copying them if( m->is_Mach() && m->as_Mach()->is_Con() && m->as_Mach()->rematerialize() ) { copy = m->clone(); // Insert the copy in the predecessor basic block pred->add_inst(copy); // Copy any flags as well _phc.clone_projs( pred, pred->end_idx(), m, copy, _phc._maxlrg ); } else { const RegMask *rm = C->matcher()->idealreg2spillmask[m->ideal_reg()]; copy = new (C) MachSpillCopyNode(m,*rm,*rm); // Find a good place to insert. Kinda tricky, use a subroutine insert_copy_with_overlap(pred,copy,phi_name,src_name); } // Insert the copy in the use-def chain n->set_req( j, copy ); _phc._cfg._bbs.map( copy->_idx, pred ); // Extend ("register allocate") the names array for the copy. _phc._names.extend( copy->_idx, phi_name ); } // End of if Phi names do not match } // End of for all inputs to Phi } else { // End of if Phi // Now check for 2-address instructions uint idx; if( n->is_Mach() && (idx=n->as_Mach()->two_adr()) ) { // Get the chosen name for the Node uint name = _phc.Find( n ); assert( name, "no 2-address specials" ); // Check for name mis-match on the 2-address input Node *m = n->in(idx); if( _phc.Find(m) != name ) { Node *copy; assert(!m->is_Con() || m->is_Mach(), "all Con must be Mach"); // At this point it is unsafe to extend live ranges (6550579). // Rematerialize only constants as we do for Phi above. if( m->is_Mach() && m->as_Mach()->is_Con() && m->as_Mach()->rematerialize() ) { copy = m->clone(); // Insert the copy in the basic block, just before us b->_nodes.insert( l++, copy ); if( _phc.clone_projs( b, l, m, copy, _phc._maxlrg ) ) l++; } else { const RegMask *rm = C->matcher()->idealreg2spillmask[m->ideal_reg()]; copy = new (C) MachSpillCopyNode( m, *rm, *rm ); // Insert the copy in the basic block, just before us b->_nodes.insert( l++, copy ); } // Insert the copy in the use-def chain n->set_req(idx, copy ); // Extend ("register allocate") the names array for the copy. _phc._names.extend( copy->_idx, name ); _phc._cfg._bbs.map( copy->_idx, b ); } } // End of is two-adr // Insert a copy at a debug use for a lrg which has high frequency if( b->_freq < OPTO_DEBUG_SPLIT_FREQ || b->is_uncommon(_phc._cfg._bbs) ) { // Walk the debug inputs to the node and check for lrg freq JVMState* jvms = n->jvms(); uint debug_start = jvms ? jvms->debug_start() : 999999; uint debug_end = jvms ? jvms->debug_end() : 999999; for(uint inpidx = debug_start; inpidx < debug_end; inpidx++) { // Do not split monitors; they are only needed for debug table // entries and need no code. if( jvms->is_monitor_use(inpidx) ) continue; Node *inp = n->in(inpidx); uint nidx = _phc.n2lidx(inp); LRG &lrg = lrgs(nidx); // If this lrg has a high frequency use/def if( lrg._maxfreq >= _phc.high_frequency_lrg() ) { // If the live range is also live out of this block (like it // would be for a fast/slow idiom), the normal spill mechanism // does an excellent job. If it is not live out of this block // (like it would be for debug info to uncommon trap) splitting // the live range now allows a better allocation in the high // frequency blocks. // Build_IFG_virtual has converted the live sets to // live-IN info, not live-OUT info. uint k; for( k=0; k < b->_num_succs; k++ ) if( _phc._live->live(b->_succs[k])->member( nidx ) ) break; // Live in to some successor block? if( k < b->_num_succs ) continue; // Live out; do not pre-split // Split the lrg at this use const RegMask *rm = C->matcher()->idealreg2spillmask[inp->ideal_reg()]; Node *copy = new (C) MachSpillCopyNode( inp, *rm, *rm ); // Insert the copy in the use-def chain n->set_req(inpidx, copy ); // Insert the copy in the basic block, just before us b->_nodes.insert( l++, copy ); // Extend ("register allocate") the names array for the copy. _phc.new_lrg( copy, _phc._maxlrg++ ); _phc._cfg._bbs.map( copy->_idx, b ); //tty->print_cr("Split a debug use in Aggressive Coalesce"); } // End of if high frequency use/def } // End of for all debug inputs } // End of if low frequency safepoint } // End of if Phi } // End of for all instructions } // End of for all blocks }
void buildModChain(FHEcontext &context, long nLevels, long nDgts,long extraBits) { #ifdef NO_HALF_SIZE_PRIME long nPrimes = nLevels; #else long nPrimes = (nLevels+1)/2; // The first prime should be of half the size. The code below tries to find // a prime q0 of this size where q0-1 is divisible by 2^k * m for some k>1. long twoM = 2 * context.zMStar.getM(); long bound = (1L << (context.bitsPerLevel-1)); while (twoM < bound/(2*context.bitsPerLevel)) twoM *= 2; // divisible by 2^k * m for a larger k bound = bound - (bound % twoM) +1; // = 1 mod 2m long q0 = context.AddPrime(bound, twoM, false); // add next prime to chain assert(q0 != 0); nPrimes--; #endif // Choose the next primes as large as possible if (nPrimes>0) AddPrimesByNumber(context, nPrimes); // calculate the size of the digits if (nDgts > nPrimes) nDgts = nPrimes; // sanity checks if (nDgts <= 0) nDgts = 1; context.digits.resize(nDgts); // allocate space IndexSet s1; double sizeSoFar = 0.0; double maxDigitSize = 0.0; if (nDgts>1) { // we break ciphetext into a few digits when key-switching double dsize = context.logOfProduct(context.ctxtPrimes)/nDgts; // estimate // A hack: we break the current digit after the total size of all digits // so far "almost reaches" the next multiple of dsize, upto 1/3 of a level double target = dsize-(context.bitsPerLevel/3.0); long idx = context.ctxtPrimes.first(); for (long i=0; i<nDgts-1; i++) { // set all digits but the last IndexSet s; while (idx <= context.ctxtPrimes.last() && (empty(s)||sizeSoFar<target)) { s.insert(idx); sizeSoFar += log((double)context.ithPrime(idx)); idx = context.ctxtPrimes.next(idx); } assert (!empty(s)); context.digits[i] = s; s1.insert(s); double thisDigitSize = context.logOfProduct(s); if (maxDigitSize < thisDigitSize) maxDigitSize = thisDigitSize; target += dsize; } // The ctxt primes that are left (if any) form the last digit IndexSet s = context.ctxtPrimes / s1; if (!empty(s)) { context.digits[nDgts-1] = s; double thisDigitSize = context.logOfProduct(s); if (maxDigitSize < thisDigitSize) maxDigitSize = thisDigitSize; } else { // If last digit is empty, remove it nDgts--; context.digits.resize(nDgts); } } else { // only one digit maxDigitSize = context.logOfProduct(context.ctxtPrimes); context.digits[0] = context.ctxtPrimes; } // Add special primes to the chain for the P factor of key-switching long p2r = context.alMod.getPPowR(); double sizeOfSpecialPrimes = maxDigitSize + log(nDgts) + log(context.stdev *2) + log((double)p2r) + (extraBits*log(2.0)); AddPrimesBySize(context, sizeOfSpecialPrimes, true); }