Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-17 08:35:35

0001 #include <VecGeom/surfaces/conv/LogicHelper.h>
0002 #include <VecGeom/surfaces/Model.h>
0003 #include <VecGeom/volumes/BooleanVolume.h>
0004 #include <VecGeom/management/Logger.h>
0005 
0006 // #define SURF_DEBUG_LOGIC
0007 
0008 namespace vgbrep {
0009 namespace logichelper {
0010 
0011 bool string_to_logic(std::string s, LogicExpressionCPU &logic)
0012 {
0013   // remove white spaces
0014   logic.clear();
0015   s.erase(std::remove_if(s.begin(), s.end(), [](unsigned char x) { return std::isspace(x); }), s.end());
0016   std::string buff;
0017   logic_int next_operand  = 0;
0018   logic_int next_operator = 0;
0019   size_t pos              = 0;
0020   int num_lplus           = 0;
0021   int num_lminus          = 0;
0022   while (pos < s.length()) {
0023     next_operator = 0;
0024     switch (s[pos]) {
0025     case '(':
0026       next_operator = lplus;
0027       num_lplus++;
0028       break;
0029     case ')':
0030       next_operator = lminus;
0031       num_lminus++;
0032       break;
0033     case '|':
0034       next_operator = lor;
0035       break;
0036     case '&':
0037       next_operator = land;
0038       break;
0039     case '!':
0040       next_operator = lnot;
0041       break;
0042     default:
0043       buff += s[pos];
0044     };
0045     pos++;
0046     if (next_operator > 0 || pos == s.length()) {
0047       // check if the buffer is not empty
0048       if (buff.length() > 0) {
0049         try {
0050           next_operand = std::stoi(buff);
0051         } catch (std::invalid_argument const &ex) {
0052           std::cout << "std::invalid_argument::what(): " << ex.what() << " \"" << buff << "\"\n ";
0053           return false;
0054         }
0055         logic.push_back(next_operand);
0056         buff.clear();
0057       }
0058       if (next_operator > 0) logic.push_back(next_operator);
0059     }
0060   }
0061   if (num_lplus != num_lminus) {
0062     std::cout << "logic parantheses mismatch\n";
0063     return false;
0064   }
0065   return true;
0066 }
0067 
0068 char logic_to_char(logic_int item)
0069 {
0070   switch (item) {
0071   case ltrue:
0072     return '1';
0073   case lfalse:
0074     return '0';
0075   case lplus:
0076     return '(';
0077   case lminus:
0078     return ')';
0079   case lor:
0080     return '|';
0081   case land:
0082     return '&';
0083   case lnot:
0084     return '!';
0085   };
0086   return '0' + item;
0087 }
0088 
0089 void print_item(logic_int item)
0090 {
0091   if (LogicExpression::is_operator_token(item)) {
0092     switch (item) {
0093     case ltrue:
0094       printf("ltrue ");
0095       break;
0096     case lfalse:
0097       printf("lfalse ");
0098       break;
0099     case lplus:
0100       printf("( ");
0101       break;
0102     case lminus:
0103       printf(") ");
0104       break;
0105     case lor:
0106       printf("| ");
0107       break;
0108     case land:
0109       printf("& ");
0110       break;
0111     case lnot:
0112       printf("!");
0113     };
0114   } else {
0115     printf("%d ", item);
0116   }
0117 }
0118 
0119 void print_logic(LogicExpressionCPU const &logic, int istart, int iend, bool jumps)
0120 {
0121   size_t ilast = (iend >= 0) ? size_t(iend) : logic.size() - 1;
0122   for (size_t i = istart; i <= ilast; ++i) {
0123     print_item(logic[i]);
0124     if (jumps && (logic[i] == land || logic[i] == lor)) i++;
0125   }
0126   printf("\n");
0127 }
0128 
0129 void print_logic(LogicExpression const &logic, int istart, int iend, bool jumps)
0130 {
0131   size_t ilast = (iend >= 0) ? size_t(iend) : logic.size() - 1;
0132   for (size_t i = istart; i <= ilast; ++i) {
0133     print_item(logic[i]);
0134     if (jumps && (logic[i] == land || logic[i] == lor)) i++;
0135   }
0136   printf("\n");
0137 }
0138 
0139 void remove_range(LogicExpressionCPU &logic, size_t istart, size_t iend)
0140 {
0141   for (size_t i = iend + 1; i < logic.size(); ++i)
0142     logic[i - iend + istart - 1] = logic[i]; // shift left
0143   for (size_t i = 0; i < iend - istart + 1; ++i)
0144     logic.pop_back();
0145 }
0146 
0147 void remove_parentheses(LogicExpressionCPU &logic, size_t start, size_t end)
0148 {
0149   VECGEOM_ASSERT(logic[start] == lplus && logic[end] == lminus);
0150   for (size_t i = start + 1; i < end; ++i)
0151     logic[i - 1] = logic[i]; // shift left
0152   for (size_t i = end + 1; i < logic.size(); ++i)
0153     logic[i - 2] = logic[i];
0154   logic.pop_back();
0155   logic.pop_back();
0156 }
0157 
0158 void insert_jumps(LogicExpressionCPU &logic)
0159 {
0160   size_t i = 0;
0161   while (i < logic.size()) {
0162     if (logic[i] == land || logic[i] == lor) {
0163       // insert jump placeholder just after the operation
0164       logic.insert(logic.begin() + i + 1, 0);
0165     }
0166     i++;
0167   }
0168   int depth = 0;
0169   for (i = 0; i < logic.size(); ++i) {
0170     if (logic[i] == lplus)
0171       depth++;
0172     else if (logic[i] == lminus)
0173       depth--;
0174     else if (logic[i] == land || logic[i] == lor) {
0175       auto d = depth;
0176       auto j = i + 1;
0177       VECGEOM_VALIDATE(j + 1 < logic.size(), << "cannot end expression with an operator");
0178       // scan for next operator at the same depth or end parenthesis
0179       while (++j < logic.size()) {
0180         if (logic[j] == lplus) {
0181           d++;
0182         } else if (d == depth && (logic[j] == lminus || logic[j] == land || logic[j] == lor))
0183           break;
0184         else if (logic[j] == lminus)
0185           d--;
0186       }
0187       logic[++i] = j;
0188     }
0189   }
0190 }
0191 
0192 bool is_negated(int isurf, LogicExpressionCPU &logic)
0193 {
0194   // Find if a given surface is negated in the logic
0195   for (size_t i = 0; i < logic.size(); ++i) {
0196     if (logic[i] == isurf) return false;
0197     if (logic[i] == lnot && logic[++i] == isurf) return true;
0198   }
0199   // It may happen that a surface is not added explicitly to the logic
0200   return false;
0201 }
0202 
0203 size_t find_matching_parenthesis(LogicExpressionCPU &logic, size_t start)
0204 {
0205   // logic[start] must be lplus
0206   VECGEOM_ASSERT(logic[start] == lplus);
0207   int ldepth = 0;
0208   for (size_t i = start; i < logic.size(); ++i) {
0209     switch (logic[i]) {
0210     case lminus:
0211       ldepth--;
0212       VECGEOM_ASSERT(ldepth >= 0);
0213       if (ldepth == 0) return i;
0214       break;
0215     case lplus:
0216       ldepth++;
0217       break;
0218     }
0219   }
0220   return logic.size();
0221 }
0222 
0223 LogicExpressionConstruct::LogicExpressionConstruct(LogicExpressionCPU const &logic)
0224 try : fLogic(logic) {
0225   // Decompose expression in operands
0226   //  scan expression
0227   int num_operands     = 0;
0228   size_t start_operand = 0;
0229   size_t end_operand   = 0;
0230   int ldepth           = 0;
0231 
0232   auto add_operand = [&]() {
0233     LogicExpressionCPU current_operand;
0234     for (size_t i = start_operand; i <= end_operand; ++i)
0235       current_operand.push_back(fLogic[i]);
0236     num_operands++;
0237     // Construct the expression for the current operand
0238     fOperands.push_back({current_operand});
0239   };
0240 
0241   auto throw_error = [&](const char *what, size_t index) {
0242     Print();
0243     VECGEOM_LOG(critical) << what << " at index " << index;
0244     throw std::runtime_error(what);
0245   };
0246 
0247   // Perform some basic checks
0248   logic_int previous = -1;
0249   for (size_t i = 0; i < fLogic.size(); ++i) {
0250     auto item        = fLogic[i];
0251     bool is_operator = (item == land) || (item == lor);
0252     if (i == 0) {
0253       if (is_operator || item == lminus) throw_error("illegal first item", i);
0254       previous = item;
0255       continue;
0256     }
0257     bool last_operator = (previous == land) || (previous == lor);
0258     bool last_operand  = !LogicExpression::is_operator_token(previous);
0259     if (i == fLogic.size() - 1) {
0260       if (is_operator || item == lnot || item == lplus) throw_error("illegal last item", i);
0261     }
0262 
0263     switch (item) {
0264     case lminus:
0265       // cannot come after a lplus, operator, or lnot
0266       if (previous == lplus || previous == lnot || last_operator) throw_error("illegal follow-up item ", i);
0267       break;
0268     case land:
0269     case lor:
0270       // cannot come after an operator an lplus or a lnot
0271       if (previous == lplus || previous == lnot || last_operator) throw_error("illegal follow-up item ", i);
0272       break;
0273     default:
0274       // cannot come after lminus or operand
0275       if (previous == lminus || last_operand) throw_error("illegal follow-up item ", i);
0276     }
0277     previous = item;
0278   }
0279 
0280   // Determine the expression complexity
0281   for (auto item : fLogic) {
0282     if (item == land || item == lor) {
0283       fComplexity++;
0284     }
0285   }
0286   if (fComplexity == 0) fHasScope = false;
0287 
0288 #ifdef SURF_DEBUG_LOGIC
0289   std::cout << "constructing logic with complexity " << fComplexity << ": ";
0290   print_logic(fLogic, 0, -1, false);
0291 #endif
0292 
0293   // Count the operands
0294   int noperands   = 1;
0295   bool simplified = true;
0296   while (simplified && noperands == 1) {
0297     simplified = false;
0298     for (size_t i = 0; i < fLogic.size(); ++i) {
0299       switch (fLogic[i]) {
0300       case lminus:
0301         ldepth--;
0302         break;
0303       case lplus:
0304         ldepth++;
0305         break;
0306       case land:
0307       case lor:
0308         if (ldepth == 0) noperands++;
0309       }
0310     }
0311 
0312     if (noperands == 1) {
0313       // If there is a single operand, extract negation and/or parentheses
0314 
0315       simplified = false;
0316       while (fLogic[0] == lnot) {
0317         fNegated   = !fNegated;
0318         simplified = true;
0319         remove_range(fLogic, 0, 0);
0320       }
0321       // Remove external parentheses if any left
0322       while (*fLogic.begin() == lplus && find_matching_parenthesis(fLogic, 0) == fLogic.size() - 1) {
0323         remove_parentheses(fLogic, 0, fLogic.size() - 1);
0324         simplified = true;
0325         fHasScope  = true;
0326       }
0327       if (simplified) {
0328 #ifdef SURF_DEBUG_LOGIC
0329         printf("simplified operand: ");
0330         print_logic(fLogic, 0, -1, false);
0331 #endif
0332       }
0333     }
0334   }
0335 
0336   // Decompose the logic expression
0337   for (size_t i = 0; i < fLogic.size(); ++i) {
0338     // scan for next operator
0339     switch (fLogic[i]) {
0340     case lminus:
0341       ldepth--;
0342       if (ldepth < 0) {
0343         VECGEOM_LOG(critical) << "LogicExpressionConstruct: parentheses mismatch at index " << i;
0344         throw std::runtime_error("parentheses mismatch");
0345       }
0346       break;
0347     case lplus:
0348       ldepth++;
0349       break;
0350     case land:
0351     case lor:
0352       if (ldepth == 0) {
0353         fOperators.push_back(fLogic[i]);
0354         if (i > start_operand) {
0355           end_operand = i - 1;
0356           add_operand();
0357           start_operand = i + 1;
0358         }
0359       }
0360       break;
0361     };
0362   }
0363   if (ldepth != 0) {
0364     throw std::runtime_error("parentheses mismatch");
0365   }
0366   if (fComplexity > 0 && start_operand < fLogic.size()) {
0367     end_operand = fLogic.size() - 1;
0368     add_operand();
0369   }
0370 } catch (const std::exception &e) {
0371   VECGEOM_LOG(critical) << "exception " << e.what();
0372 }
0373 
0374 LogicExpressionConstruct &LogicExpressionConstruct::operator&=(LogicExpressionConstruct const &other)
0375 {
0376   Concatenate(other, land);
0377   return *this;
0378 }
0379 
0380 LogicExpressionConstruct &LogicExpressionConstruct::operator|=(LogicExpressionConstruct const &other)
0381 {
0382   Concatenate(other, lor);
0383   return *this;
0384 }
0385 
0386 void LogicExpressionConstruct::Concatenate(LogicExpressionConstruct const &other, logic_int op_concat)
0387 {
0388   // Create operand if none exist
0389 #ifdef SURF_DEBUG_LOGIC
0390   printf("Concatenating : ");
0391   Print();
0392   printf("         with : ");
0393   other.Print();
0394 #endif
0395   if (!fOperands.size()) {
0396     if (fNegated) {
0397       fLogic.insert(fLogic.begin(), lnot);
0398       fNegated = false;
0399     }
0400     fOperands.push_back({fLogic});
0401   }
0402   fOperands.push_back(other);
0403   fOperators.push_back(op_concat);
0404   fComplexity++;
0405 #ifdef SURF_DEBUG_LOGIC
0406   printf("       result : ");
0407   Print();
0408 #endif
0409 }
0410 
0411 void LogicExpressionConstruct::PushNegation(bool neg)
0412 {
0413   fNegated ^= neg;
0414   if (!fComplexity) {
0415     if (fNegated) fLogic.insert(fLogic.begin(), lnot);
0416     fNegated = false;
0417   }
0418   for (auto &operand : fOperands)
0419     operand.PushNegation(fNegated);
0420   for (size_t i = 0; i < fOperators.size(); ++i) {
0421     if (fNegated) {
0422       if (fOperators[i] == land)
0423         fOperators[i] = lor;
0424       else if (fOperators[i] == lor)
0425         fOperators[i] = land;
0426     }
0427   }
0428   fNegated = false;
0429 }
0430 
0431 bool LogicExpressionConstruct::RemoveScope(logic_int logic_op)
0432 {
0433   // Remove scope if all operators in the expression match the input one
0434   bool removed_scope = false;
0435   if (fHasScope) {
0436 #ifdef SURF_DEBUG_LOGIC
0437     printf("removing scope for operation ");
0438     print_item(logic_op);
0439     printf("in operand: ");
0440     Print();
0441 #endif
0442     removed_scope = true;
0443     for (auto op : fOperators) {
0444       if (op != logic_op) {
0445         removed_scope = false;
0446         break;
0447       }
0448     }
0449     if (removed_scope) fHasScope = false;
0450 #ifdef SURF_DEBUG_LOGIC
0451     printf("after scope removal: ");
0452     Print();
0453 #endif
0454   }
0455   RemoveChildrenScopes();
0456   return removed_scope;
0457 }
0458 
0459 void LogicExpressionConstruct::RemoveChildrenScopes(bool top)
0460 {
0461   // Remove scope for children operands for surrounding operators
0462 #ifdef SURF_DEBUG_LOGIC
0463   printf("removing children scopes for: ");
0464   Print();
0465 #endif
0466   if (top) fHasScope = false;
0467   if (fOperators.size() == 0) return;
0468 
0469   for (size_t i = 0; i < fOperands.size(); ++i) {
0470     size_t sjump        = 0;
0471     auto &operand       = fOperands[i];
0472     logic_int op_before = (i > 0) ? fOperators[i - 1] : fOperators[i];
0473     logic_int op_after  = (i < fOperands.size() - 1) ? fOperators[i] : fOperators[i - 1];
0474     bool match_op       = op_before == op_after;
0475     if (match_op) {
0476       bool removed_scope = operand.RemoveScope(op_before);
0477       if (removed_scope) {
0478         // pull the operand expression up
0479         fComplexity += operand.fComplexity;
0480         sjump = 0;
0481         if (operand.fComplexity > 0) {
0482           sjump = operand.fOperands.size() - 1;
0483           fOperators.insert(fOperators.begin() + i, operand.fOperators.begin(), operand.fOperators.end());
0484           fOperands.insert(fOperands.begin() + i + 1, operand.fOperands.begin(), operand.fOperands.end());
0485           fOperands.erase(fOperands.begin() + i);
0486         }
0487       }
0488     } else {
0489       operand.RemoveChildrenScopes();
0490     }
0491 #ifdef SURF_DEBUG_LOGIC
0492     printf("  after operand %ld : ", i);
0493     Print();
0494 #endif
0495     i += sjump;
0496   }
0497 #ifdef SURF_DEBUG_LOGIC
0498   printf("after removing children scopes: ");
0499   Print();
0500 #endif
0501 }
0502 
0503 void LogicExpressionConstruct::Print() const
0504 {
0505   LogicExpressionCPU logic;
0506   GetLogicExpression(logic);
0507   print_logic(logic, 0, -1, false);
0508 }
0509 
0510 void LogicExpressionConstruct::GivePrecedenceToAnd()
0511 {
0512   // If the expression contains both AND and OR operators, swap the expression so that AND has precedence
0513   bool has_and = std::find(fOperators.begin(), fOperators.end(), land) != fOperators.end();
0514   bool has_or  = std::find(fOperators.begin(), fOperators.end(), lor) != fOperators.end();
0515   if (!has_and || !has_or) return;
0516 
0517   while (fOperators[0] == lor) {
0518     // if the first operator is an OR, move the first operand to the end
0519     std::rotate(fOperators.begin(), fOperators.begin() + 1, fOperators.end());
0520     std::rotate(fOperands.begin(), fOperands.begin() + 1, fOperands.end());
0521   }
0522 
0523   // Add parentheses to AND groups if they are not at the beginning
0524   // find position of first AND after an OR
0525   size_t ior  = std::distance(fOperators.begin(), std::find(fOperators.begin(), fOperators.end(), lor));
0526   size_t iand = std::distance(fOperators.begin(), std::find(fOperators.begin() + ior + 1, fOperators.end(), land));
0527   while (iand < fOperators.size()) {
0528     size_t iand_last = iand;
0529     for (size_t i = iand + 1; i < fOperators.size() && fOperators[i] == land; ++i)
0530       iand_last = i;
0531     // Add scope for the AND group
0532     for (size_t i = iand; i <= iand_last; ++i) {
0533       fOperands[iand] &= fOperands[i + 1];
0534     }
0535     VECGEOM_ASSERT(
0536         !fOperands[iand].fNegated); // this should be the case, if not we need to push negation to logic expression
0537     fOperands[iand].fHasScope = true;
0538     fOperands.erase(fOperands.begin() + iand + 1, fOperands.begin() + iand_last + 2);
0539     fOperators.erase(fOperators.begin() + iand, fOperators.begin() + iand_last + 1);
0540     ior  = std::distance(fOperators.begin(), std::find(fOperators.begin() + iand + 1, fOperators.end(), lor));
0541     iand = std::distance(fOperators.begin(), std::find(fOperators.begin() + ior + 1, fOperators.end(), land));
0542   }
0543 }
0544 
0545 void LogicExpressionConstruct::SwapByComplexity()
0546 {
0547   // Find range for which swapping is allowed
0548   if (fComplexity == 0) return;
0549 #ifdef SURF_DEBUG_LOGIC
0550   printf("SwapByComplexity start: ");
0551   Print();
0552 #endif
0553   size_t istart_op = 0;
0554   size_t iend_op   = 0;
0555   auto op          = fOperators[istart_op];
0556   while (istart_op < fOperators.size()) {
0557     for (size_t i = istart_op + 1; i < fOperators.size(); ++i) {
0558       if (fOperators[i] == op)
0559         iend_op = i;
0560       else
0561         break;
0562     }
0563     size_t istart = istart_op;
0564     size_t iend   = (op == land) ? iend_op + 1 : iend_op;
0565     iend          = std::min(iend, fOperands.size() - 1);
0566     if (iend > istart) {
0567       // swap by complexity
0568 #ifdef SURF_DEBUG_LOGIC
0569       printf("sorting operands [%ld, %ld]\n", istart, iend);
0570 #endif
0571       for (size_t iop = istart; iop < iend; ++iop) {
0572         for (size_t jop = iop + 1; jop <= iend; ++jop) {
0573           auto c1 = fOperands[iop].fComplexity;
0574           auto c2 = fOperands[jop].fComplexity;
0575           if (c1 > c2) {
0576             std::iter_swap(fOperands.begin() + iop, fOperands.begin() + jop);
0577 #ifdef SURF_DEBUG_LOGIC
0578             printf("after swapping %ld (compl=%d) <-> %ld (compl=%d): ", iop, c1, jop, c2);
0579             Print();
0580 #endif
0581           }
0582         }
0583       }
0584     }
0585     istart_op = iend_op + 1;
0586     if (istart_op < fOperators.size()) {
0587       op = fOperators[istart_op];
0588       if (op == lor) {
0589         istart_op++;
0590         if (istart_op < fOperators.size()) op = fOperators[istart_op];
0591       }
0592     }
0593     iend_op = istart_op;
0594   }
0595   // Now process children
0596   for (auto &operand : fOperands)
0597     operand.SwapByComplexity();
0598 }
0599 
0600 void LogicExpressionConstruct::GetLogicExpression(LogicExpressionCPU &logic) const
0601 {
0602   if (fNegated) logic.push_back(lnot);
0603   if (fHasScope) logic.push_back(lplus);
0604   if (fComplexity == 0) {
0605     for (auto &item : fLogic)
0606       logic.push_back(item);
0607   } else {
0608     for (size_t i = 0; i < fOperands.size(); ++i) {
0609       fOperands[i].GetLogicExpression(logic);
0610       if (i < fOperators.size()) logic.push_back(fOperators[i]);
0611     }
0612   }
0613   if (fHasScope) logic.push_back(lminus);
0614 }
0615 
0616 int LogicExpressionConstruct::GetNumOperands() const
0617 {
0618   int noperands = (fOperands.size() == 0) ? 1 : 0;
0619   for (auto const &operand : fOperands)
0620     noperands += operand.GetNumOperands();
0621   return noperands;
0622 }
0623 
0624 void LogicExpressionConstruct::Simplify(LogicExpressionCPU &logic)
0625 {
0626   PushNegation();
0627   RemoveChildrenScopes(true);
0628   GivePrecedenceToAnd();
0629   SwapByComplexity();
0630   logic.clear();
0631   GetLogicExpression(logic);
0632 }
0633 
0634 int max_operand(LogicExpressionCPU const &logic)
0635 {
0636   int max_op = -1;
0637   for (auto const &item : logic) {
0638     if (LogicExpression::is_operator_token(item)) continue;
0639     max_op = std::max(max_op, int(item));
0640   }
0641   return max_op;
0642 }
0643 
0644 void substitute_logic(LogicExpressionCPU const &logic, LogicExpressionCPU &substutute_logic, const bool *values)
0645 {
0646   substutute_logic.clear();
0647   for (auto item : logic) {
0648     if (LogicExpression::is_operator_token(item))
0649       substutute_logic.push_back(item);
0650     else
0651       substutute_logic.push_back(logic_int(values[item]));
0652   }
0653 }
0654 
0655 bool evaluate_logic(LogicExpressionCPU const &logic, const bool *values, int &num_eval)
0656 {
0657   auto test_bit   = [](unsigned bset, int bit) { return (bset & (unsigned(1) << bit)) > 0; };
0658   auto set_bit    = [](unsigned &bset, int bit) { bset |= unsigned(1) << bit; };
0659   auto reset_bit  = [](unsigned &bset, int bit) { bset &= ~(unsigned(1) << bit); };
0660   auto swap_bit   = [](unsigned &bset, int bit) { bset ^= unsigned(1) << bit; };
0661   unsigned stack  = 0;
0662   unsigned negate = 0;
0663   int depth       = 0;
0664   num_eval        = 0;
0665   bool result     = false;
0666   unsigned i;
0667   for (i = 0; i < logic.size(); ++i) {
0668     switch (logic[i]) {
0669     case lplus:
0670       depth++;
0671       break;
0672     case lminus:
0673       result = test_bit(stack, depth);
0674       reset_bit(negate, depth--);
0675       result ^= test_bit(negate, depth);
0676       if (result)
0677         set_bit(stack, depth);
0678       else
0679         reset_bit(stack, depth);
0680       break;
0681     case lnot:
0682       swap_bit(negate, depth);
0683       break;
0684     case lor:
0685       if (test_bit(stack, depth))
0686         i = logic[i + 1] - 1;
0687       else
0688         i++;
0689       break;
0690     case land:
0691       if (!test_bit(stack, depth))
0692         i = logic[i + 1] - 1;
0693       else
0694         i++;
0695       break;
0696     default:
0697       // This is an operand
0698       result = values[int(logic[i])];
0699       result ^= test_bit(negate, depth);
0700       reset_bit(negate, depth);
0701       num_eval++;
0702       // We can ignore the previous value because of short-circuiting
0703       if (result)
0704         set_bit(stack, depth);
0705       else
0706         reset_bit(stack, depth);
0707     }
0708   }
0709   VECGEOM_ASSERT(depth == 0);
0710   return (stack & 1) > 0;
0711 }
0712 
0713 } // namespace logichelper
0714 } // namespace vgbrep