示例#1
0
int
pathcmp(const char *p1, const char *p2)
{
    char *s1, *s2;
    int code;
    char tmp1[MAXPATHLEN], tmp2[MAXPATHLEN];

    if (strlen(p1) < sizeof(tmp1) && strlen(p2) < sizeof(tmp2)) {
	/* put the names into canonical form if they are not */
	p1 = strcpy(tmp1, p1);
	p2 = strcpy(tmp2, p2);

	TRACE(("\n\t(%s %s)", p1, p2))
	    while (*p1 == PATH_SLASH && *p2 == PATH_SLASH)
	    p1++, p2++;		/* faster than strcmp... */
	while (*p1 && *p2) {
	    CUT(p1, s1);
	    CUT(p2, s2);
	    TRACE((" [%s %s]", p1, p2))
		if ((code = strcmp(p1, p2)) != 0)
		return (code);
	    if ((s1 != 0) || (s2 != 0)) {
		if (s2 == 0)
		    return (GT);
		if (s1 == 0)
		    return (LT);
		p1 = s1 + 1;
		p2 = s2 + 1;
	    } else {
		break;
	    }
	}
	code = (*p1 - *p2);
    } else {
void IntervalVariable::propagateNC()
{
    if (ToulBar2::verbose >= 3) cout << "propagateNC for " << getName() << endl;
    if (CUT(getInfCost() + wcsp->getLb(), wcsp->getUb())) increaseFast(getInf() + 1);
    if (CUT(getSupCost() + wcsp->getLb(), wcsp->getUb())) decreaseFast(getSup() - 1);
    if (getInfCost() > getSupCost()) {
        setMaxUnaryCost(getInf(), getInfCost());
    } else {
        setMaxUnaryCost(getSup(), getSupCost());
    }
}
bool IntervalVariable::verifyNC()
{
    if (CUT(getInfCost() + wcsp->getLb(),wcsp->getUb())) {
        cout << *this << " has inf cost not NC!" << endl;
        return false;
    }
    if (CUT(getSupCost() + wcsp->getLb(),wcsp->getUb())) {
        cout << *this << " has sup cost not NC!" << endl;
        return false;
    }
    return true;
}
pair<pair<Cost, Cost>, pair<Cost, Cost> > BinaryConstraint::getMaxCost(int varIndex, Value a, Value b)
{
    //    	cout << "getMaxCost(" << getVar(varIndex)->getName() << ") " << a << " <-> " << b << endl << *this << endl;
    Cost maxcosta = MIN_COST;
    Cost diffcosta = MIN_COST;
    Cost maxcostb = MIN_COST;
    Cost diffcostb = MIN_COST;
    if (varIndex == 0) {
        Cost ucosta = x->getCost(a);
        Cost ucostb = x->getCost(b);
        for (EnumeratedVariable::iterator iterY = y->begin(); iterY != y->end(); ++iterY) {
            Cost costa = getCost(a, *iterY);
            Cost costb = getCost(b, *iterY);
            if (costa > maxcosta)
                maxcosta = costa;
            if (costb > maxcostb)
                maxcostb = costb;
            Cost ucosty = y->getCost(*iterY);
            if (!CUT(ucostb + costb + ucosty + wcsp->getLb(), wcsp->getUb())) {
                if (costa - costb > diffcosta)
                    diffcosta = costa - costb;
            }
            if (!CUT(ucosta + costa + ucosty + wcsp->getLb(), wcsp->getUb())) {
                if (costb - costa > diffcostb)
                    diffcostb = costb - costa;
            }
        }
    } else {
        Cost ucosta = y->getCost(a);
        Cost ucostb = y->getCost(b);
        for (EnumeratedVariable::iterator iterX = x->begin(); iterX != x->end(); ++iterX) {
            Cost costa = getCost(*iterX, a);
            Cost costb = getCost(*iterX, b);
            if (costa > maxcosta)
                maxcosta = costa;
            if (costb > maxcostb)
                maxcostb = costb;
            Cost ucostx = x->getCost(*iterX);
            if (!CUT(ucostb + costb + ucostx + wcsp->getLb(), wcsp->getUb())) {
                if (costa - costb > diffcosta)
                    diffcosta = costa - costb;
            }
            if (!CUT(ucosta + costa + ucostx + wcsp->getLb(), wcsp->getUb())) {
                if (costb - costa > diffcostb)
                    diffcostb = costb - costa;
            }
        }
    }
    assert(maxcosta >= diffcosta);
    assert(maxcostb >= diffcostb);
    return make_pair(make_pair(maxcosta, diffcosta), make_pair(maxcostb, diffcostb));
}
bool BinaryConstraint::isFunctional(EnumeratedVariable* xin, EnumeratedVariable* yin, map<Value, Value>& functional)
{
    assert(xin != yin);
    assert(getIndex(xin) >= 0);
    assert(getIndex(yin) >= 0);
    bool isfunctional = true;
    functional.clear();
    for (EnumeratedVariable::iterator itx = xin->begin(); isfunctional && itx != xin->end(); ++itx) {
        bool first = true;
        for (EnumeratedVariable::iterator ity = yin->begin(); isfunctional && ity != yin->end(); ++ity) {
            if (!CUT(getCost(xin, yin, *itx, *ity) + wcsp->getLb(), wcsp->getUb())) {
                if (first) {
                    functional[*itx] = *ity;
                    first = false;
                } else {
                    isfunctional = false;
                }
            }
        }
        assert(!first); // assumes it is SAC already
    }
    if (isfunctional)
        return true;
    functional.clear();
    return false;
}
void VACVariable::VACproject(Value v, const Cost c)
{
    //   Cost oldCost = getVACCost(v);
    costs[toIndex(v)] += c;
    //   Cost newCost = getVACCost(v);

    //   if ((v == maxCostValue) || (newCost > maxCost) || CUT(wcsp->getLb() + newCost,wcsp->getUb())) {
    if (CUT(wcsp->getLb() + getCost(v), wcsp->getUb())) {
        queueNC();
    }
    //   if (oldCost == MIN_COST) {
    //     queueNC();
    //     queueDAC();
    //     queueEAC1();
    //   }
    //   if ((isNull(oldCost)) && (!isNull(newCost))) {
    //     queueVAC2();
    //   }

    //   if(v == getSupport()) {
    //     Value newSupport = getInf();
    //     Cost minCost = getCost(newSupport);
    //     EnumeratedVariable::iterator iter = begin();
    //     for (++iter; minCost > MIN_COST && iter != end(); ++iter) {
    //         Cost cost = getCost(*iter);
    //         if (cost < minCost) {
    //             minCost = cost;
    //             newSupport = *iter;
    //         }
    //     }
    // 	assert(canbe(newSupport));
    // 	//	cout << "setsupport " << wcspIndex << " " << newSupport << endl;
    // 	setSupport(newSupport);
    //   }
}
示例#7
0
文件: fbh.c 项目: nphuc/alg
int FIB_HEAP_DECREASE_KEY(node*H1,long x,long k)
{
  node* y;
  if(H1==NULL)
  {
    printf("\nNO NODE IN THE HEAP!!! ABORTING!!!!");
    return 0;
  }
  node* ptr=FIND_NODE(H1,x);
  if(ptr==NULL)
  {
    printf("\nTHE TARGET NODE NOT FOUND!!!!!");
    return 1;
  }
  // cout<<"\nptr="<<ptr->n;
  if(ptr->n<k)
  {
    printf("\nTHE ENTERED KEY IS GREATER THAN THE CURRENT VALUE!!!");
    return 0;
  }
  ptr->n=k;
  y=ptr->parent;
  if(y!=NULL&&ptr->n<y->n)
  {
    CUT(H1,ptr,y);
    CASCADE_CUT(H1,y);
  }
  if(ptr->n<H->n)
    H=ptr;//cout<<"\nH="<<ptr->n;}
    return 0;
    }
void IntervalVariable::projectInfCost(Cost cost)
{
    infCost += cost;
    assert(infCost >= MIN_COST);
    if (getInf() == maxCostValue || infCost > maxCost) queueNC();
    if (CUT(infCost + wcsp->getLb(),wcsp->getUb())) increaseFast(getInf() + 1);
}
void IntervalVariable::projectSupCost(Cost cost)
{
    supCost += cost;
    assert(supCost >= MIN_COST);
    if (getSup() == maxCostValue || supCost > maxCost) queueNC();
    if (CUT(supCost + wcsp->getLb(), wcsp->getUb())) decreaseFast(getSup() - 1);
}
示例#10
0
void Unary::propagate()
{
    if (ToulBar2::verbose >= 3) {
        print(cout);
        cout << " dxinf=" << deltaValueXinf << " dxsup=" << deltaValueXsup << endl;
    }
    wcsp->revise(this);
    set<Value>::iterator itinf = permitted.lower_bound(x->getInf());
    set<Value>::iterator itsup = permitted.upper_bound(x->getSup());
    --itsup;
    if (itinf == permitted.end() || itsup == permitted.end()) {
        // IC0 propagatation (increase global lower bound)
        deconnect();
        projectLB(penalty);
    } else {
        // propagate hard constraint
        if (CUT(wcsp->getLb()+penalty, wcsp->getUb())) {
            if (x->getInf() < *itinf) x->increase(*itinf);
            if (x->getSup() > *itsup) x->decrease(*itsup);
        }
        // BAC* propagation (increase unary costs of domain bounds)
        Value xinf = x->getInf();
        if (xinf != deltaValueXinf && xinf != deltaValueXsup && permitted.find(xinf) == permitted.end()) {
            deltaValueXinf = xinf;
            x->projectInfCost(penalty);
        }
        Value xsup = x->getSup();
        if (xsup != deltaValueXinf && xsup != deltaValueXsup && permitted.find(xsup) == permitted.end()) {
            deltaValueXsup = xsup;
            x->projectSupCost(penalty);
        }
    }
}
示例#11
0
/// \warning always returns false for cost functions in intention
bool Constraint::ishard()
{
   if (!extension()) return false;

   String tuple;
   Cost cost;
   firstlex();
   while (nextlex(tuple,cost)) {
 	if (cost > MIN_COST && !CUT(cost,wcsp->getUb())) return false;
   }
   return true;
}
示例#12
0
文件: fbh.c 项目: nphuc/alg
int CASCADE_CUT(node* H1,node* y)
{
  node* z=y->parent;
  if(z!=NULL)
  {
    if(y->mark=='F')
    {
      y->mark='T';
    }
    else
    {
      CUT(H1,y,z);
      CASCADE_CUT(H1,z);
    }

  }
}
/*
 * Propagation methods
 *
 */
bool BinaryConstraint::project(EnumeratedVariable* x, Value value, Cost cost, vector<StoreCost>& deltaCostsX)
{
    assert(ToulBar2::verbose < 4 || ((cout << "project(C" << getVar(0)->getName() << "," << getVar(1)->getName() << ", (" << x->getName() << "," << value << "), " << cost << ")" << endl), true));

    // hard binary constraint costs are not changed
    if (!CUT(cost + wcsp->getLb(), wcsp->getUb())) {
        TreeDecomposition* td = wcsp->getTreeDec();
        if (td)
            td->addDelta(cluster, x, value, cost);
        deltaCostsX[x->toIndex(value)] += cost; // Warning! Possible overflow???
        assert(getCost(x, (EnumeratedVariable*)getVarDiffFrom(x), value, getVarDiffFrom(x)->getInf()) >= MIN_COST);
        assert(getCost(x, (EnumeratedVariable*)getVarDiffFrom(x), value, getVarDiffFrom(x)->getSup()) >= MIN_COST);
    }

    Cost oldcost = x->getCost(value);
    x->project(value, cost);
#ifdef DEECOMPLETE
    getVarDiffFrom(x)->queueDEE();
#endif
    return (x->getSupport() == value || SUPPORTTEST(oldcost, cost));
}
示例#14
0
void Disjunction::propagate()
{
    if (ToulBar2::verbose >= 3) {
        print(cout);
        cout << " dxinf=" << deltaValueXinf << " dxsup=" << deltaValueXsup << " dyinf=" << deltaValueYinf << " dysup=" << deltaValueYsup << endl;
    }
    wcsp->revise(this);
    // deconnect the constraint if always satisfied
    if (x->getInf() >= y->getSup() + csty || y->getInf() >= x->getSup() + cstx) {
        deconnect();
    } else if (x->getSup() < y->getInf() + csty && y->getSup() < x->getInf() + cstx) {
        // IC0 propagatation (increase global lower bound if always unsatisfied)
        deconnect();
        if (x->unassigned()) {
            if (x->getInf() == deltaValueXinf) x->projectInfCost(-penalty);
            if (x->getSup() == deltaValueXsup) x->projectSupCost(-penalty);
        }
        if (y->unassigned()) {
            if (y->getInf() == deltaValueYinf) y->projectInfCost(-penalty);
            if (y->getSup() == deltaValueYsup) y->projectSupCost(-penalty);
        }
        projectLB(penalty);
    } else {
        // propagate hard constraint
        if (CUT(wcsp->getLb()+penalty, wcsp->getUb())) {
            if (x->getSup() < y->getInf() + csty) {
                Value newInf = x->getInf() + cstx;
                if (y->getInf() < newInf) y->increase(newInf);
                Value newSup = y->getSup() - cstx;
                if (x->getSup() > newSup) x->decrease(newSup);
            } else if (y->getSup() < x->getInf() + cstx) {
                Value newInf = y->getInf() + csty;
                if (x->getInf() < newInf) x->increase(newInf);
                Value newSup = x->getSup() - csty;
                if (y->getSup() > newSup) y->decrease(newSup);
            }
        }

        // BAC* propagation (increase unary costs of domain bounds)
        if (x->unassigned()) {
            Value xinf = x->getInf();
            if (xinf != deltaValueXinf && xinf != deltaValueXsup && xinf < y->getInf() + csty && xinf > y->getSup() - cstx) {
                deltaValueXinf = xinf;
                x->projectInfCost(penalty);
            }
            Value xsup = x->getSup();
            if (xsup != deltaValueXsup && xsup != deltaValueXinf && xsup < y->getInf() + csty && xsup > y->getSup() - cstx) {
                deltaValueXsup = xsup;
                x->projectSupCost(penalty);
            }
        }
        if (y->unassigned()) {
            Value yinf = y->getInf();
            if (yinf != deltaValueYinf && yinf != deltaValueYsup && yinf < x->getInf() + cstx && yinf > x->getSup() - csty) {
                deltaValueYinf = yinf;
                y->projectInfCost(penalty);
            }
            Value ysup = y->getSup();
            if (ysup != deltaValueYsup && ysup != deltaValueYinf && ysup < x->getInf() + cstx && ysup > x->getSup() - csty) {
                deltaValueYsup = ysup;
                y->projectSupCost(penalty);
            }
        }
    }
}
示例#15
0
void SpecialDisjunction::propagate()
{
    if (ToulBar2::verbose >= 3) {
        print(cout);
        cout << "deltaCost= " << deltaCost << " dxinf=" << deltaValueXinf << " dxsup=" << deltaValueXsup << " dyinf=" << deltaValueYinf << " dysup=" << deltaValueYsup << endl;
    }
    wcsp->revise(this);
    if (x->getSup()>xinfty) x->decrease(xinfty);
    if (y->getSup()>yinfty) y->decrease(yinfty);
    if ((x->getSup() < xinfty && y->getSup() < yinfty &&
            (x->getInf() >= y->getSup() + csty || y->getInf() >= x->getSup() + cstx)) ||
            (x->getInf() >= xinfty && y->getSup() < yinfty) ||
            (y->getInf() >= yinfty && x->getSup() < xinfty)) {
        // deconnect the constraint if always satisfied
        assert(x->getInf() < xinfty || y->getSup() >= yinfty || deltaCost == costx);
        assert(y->getInf() < yinfty || x->getSup() >= xinfty || deltaCost == costy);
        deconnect();
    } else if (x->getSup() < xinfty && y->getSup() < yinfty &&
            x->getSup() < y->getInf() + csty && y->getSup() < x->getInf() + cstx) {
        // backtrack if the constraint if always unsatisfied
        THROWCONTRADICTION;
    } else {
        if (x->getInf() < xinfty && y->getInf() < yinfty) {
            // IC0 propagatation (increase global lower bound)
            if (min(x->getSup(),xinfty-1) < y->getInf() + csty &&
                    min(y->getSup(),yinfty-1) < x->getInf() + cstx) {
                Cost cost = min(costx,costy) - deltaCost;
                if (cost > MIN_COST) {
                    deltaCost += cost;
                    projectLB(cost);
                }
            }
            // propagate hard constraint
            if ((x->getSup() < xinfty || CUT(wcsp->getLb()+costx-deltaCost, wcsp->getUb())) &&
                    min(x->getSup(),xinfty-1) < y->getInf() + csty) {
                Value newInf = min(x->getInf() + cstx, yinfty);
                if (y->getInf() < newInf) y->increase(newInf);
                if (y->getSup() < yinfty) {
                    Value newSup = y->getSup() - cstx;
                    if (x->getSup() > newSup) x->decrease(newSup);
                }
            }
            if ((y->getSup() < yinfty || CUT(wcsp->getLb()+costy-deltaCost, wcsp->getUb())) &&
                    min(y->getSup(),yinfty-1) < x->getInf() + cstx) {
                Value newInf = min(y->getInf() + csty, xinfty);
                if (x->getInf() < newInf) x->increase(newInf);
                if (x->getSup() < xinfty) {
                    Value newSup = x->getSup() - csty;
                    if (y->getSup() > newSup) y->decrease(newSup);
                }
            }
            // BAC* propagation (increase unary costs of domain bounds)
            if (x->unassigned() && y->getInf() < yinfty) {
                Value xinf = x->getInf();
                Cost cost = -((Cost) deltaCost);
                if (xinf < y->getInf() + csty && xinf > min(y->getSup(),yinfty-1) - cstx) cost += costy;
                if (xinf == deltaValueXinf) {
                    Cost delta = cost - deltaCostXinf;
                    if (delta != MIN_COST) {
                        deltaCostXinf = cost;
                        x->projectInfCost(delta);
                    }
                } else {
                    deltaValueXinf = xinf;
                    deltaCostXinf = cost;
                    x->projectInfCost(cost);
                }
            }
            if (x->unassigned() && y->getInf() < yinfty) {
                Value xsup = x->getSup();
                Cost cost = -((Cost) deltaCost);
                if (xsup==xinfty) cost += costx;
                else if (xsup < y->getInf() + csty && xsup > min(y->getSup(),yinfty-1) - cstx) cost += costy;
                if (xsup == deltaValueXsup) {
                    Cost delta = cost - deltaCostXsup;
                    if (delta != MIN_COST) {
                        deltaCostXsup = cost;
                        x->projectSupCost(delta);
                    }
                } else {
                    deltaValueXsup = xsup;
                    deltaCostXsup = cost;
                    x->projectSupCost(cost);
                }
            }
            if (y->unassigned() && x->getInf() < xinfty) {
                Value yinf = y->getInf();
                Cost cost = -((Cost) deltaCost);
                if (yinf < x->getInf() + cstx && yinf > min(x->getSup(),xinfty-1) - csty) cost += costx;
                if (yinf == deltaValueYinf) {
                    Cost delta = cost - deltaCostYinf;
                    if (delta != MIN_COST) {
                        deltaCostYinf = cost;
                        y->projectInfCost(delta);
                    }
                } else {
                    deltaValueYinf = yinf;
                    deltaCostYinf = cost;
                    y->projectInfCost(cost);
                }
            }
            if (y->unassigned() && x->getInf() < xinfty) {
                Value ysup = y->getSup();
                Cost cost = -((Cost) deltaCost);
                if (ysup==yinfty) cost += costy;
                else if (ysup < x->getInf() + cstx && ysup > min(x->getSup(),xinfty-1) - csty) cost += costx;
                if (ysup == deltaValueYsup) {
                    Cost delta = cost - deltaCostYsup;
                    if (delta != MIN_COST) {
                        deltaCostYsup = cost;
                        y->projectSupCost(delta);
                    }
                } else {
                    deltaValueYsup = ysup;
                    deltaCostYsup = cost;
                    y->projectSupCost(cost);
                }
            }
        }
    }
}
示例#16
0
void VACExtension::enforcePass2()
{
    int i0 = inconsistentVariable;
    int i, j;
    VACVariable *xi0, *xi, *xj;
    VACBinaryConstraint *cij;
    Cost tmplambda;
    Value v;

    //if (ToulBar2::verbose > 0)  cout << "VAC Enforce Pass 2" << endl;

    assert(i0 >= 0);
    xi0 = (VACVariable *) wcsp->getVar(i0);

    for (EnumeratedVariable::iterator iti0 = xi0->begin();
            iti0 != xi0->end(); ++iti0) {
        v = *iti0;
        xi0->addToK(v, 1, nbIterations);
        Cost cost = xi0->getVACCost(v);
        if (cost > MIN_COST) {
            if (cost < minlambda) {
                minlambda = cost;	// NB: we don't need to check for bottleneck here as k=1 necessarily
            }
        } else
            xi0->setMark(v, nbIterations);
    }

    while (!queueP->empty()) {
        i = queueP->top().first;
        v = queueP->top().second;
        queueP->pop();
        xi = (VACVariable *) wcsp->getVar(i);
        if (xi->isMarked(v, nbIterations)) {
            j = xi->getKiller(v);
            xj = (VACVariable *) wcsp->getVar(j);
            queueR->push(pair < int, int >(i, v));
            cij = (VACBinaryConstraint *) xi->getConstr(xj);
            assert(cij);
            //if (ToulBar2::verbose > 6) cout << "x" << xi->wcspIndex << "," << v << "   killer: " << xj->wcspIndex << endl;

            for (EnumeratedVariable::iterator itj = xj->begin();
                    itj != xj->end(); ++itj) {
                Value w = *itj;
                Cost costij = cij->getVACCost(xi, xj, v, w);
                if (costij > MIN_COST) {
                    int tmpK = xi->getK(v, nbIterations);
                    if (xj->getKiller(w) == i
                            && xj->isMarked(w, nbIterations))
                        tmpK +=
                                xj->getK(w, nbIterations);
                    if (!CUT
                            (wcsp->getLb() + costij,
                                    wcsp->getUb())) {
                        if ((costij / tmpK) < minlambda) {
                            minlambda =
                                    costij / tmpK;
                            if (minlambda < UNIT_COST) {	//A cost function bottleneck here !
                                bneckCost =
                                        costij;
                                bneckCF = cij;
                                bneckVar = -1;
                            }
                        }
                    } else {
                        if ((costij / tmpK) < minlambda) { // costij should be made infinite to avoid to decrease minlambda
                            Cost cost = tmpK * minlambda - costij;
                            assert(cost > MIN_COST);
                            assert(ToulBar2::verbose < 1 || ((cout << "inflate(C" << cij->getVar(0)->getName() << "," << cij->getVar(1)->getName() << ", (" << ((xi==cij->getVar(0))?v:w) << "," << ((xi==cij->getVar(0))?w:v) << "), " << cost << ")" << endl), true));
                            cij->addcost( xi, xj, v, w, cost );
                        }
                    }
                } else {
                    int tmpK =
                            xi->getK(v,
                                    nbIterations) -
                                    cij->getK(xj, w, nbIterations);
                    if (tmpK > 0) {
                        xj->addToK(w, tmpK,
                                nbIterations);
                        cij->setK(xj, w,
                                xi->getK(v,
                                        nbIterations),
                                        nbIterations);
                        Cost cost = xj->getVACCost(w);
                        if (cost == MIN_COST)
                            xj->setMark(w,
                                    nbIterations);
                        else if (!CUT
                                (wcsp->getLb() + cost,
                                        wcsp->getUb())) {
                            tmplambda =
                                    cost / xj->getK(w,
                                            nbIterations);
                            if (tmplambda <
                                    minlambda) {
                                minlambda =
                                        tmplambda;
                                if (minlambda < UNIT_COST) {	// A unary cost bottleneck here
                                    bneckVar
                                    = j;
                                    bneckCF
                                    =
                                            NULL;
                                    bneckCost
                                    =
                                            cost;
                                }
                            }
                        } // else cost is infinite and it will not be decreased by VACextend
                    }
                }
            }
        }
    }
    //if (maxK == 0) {
    //  maxK = wcsp->getUb() - wcsp->getLb();
    //}
    if (ToulBar2::verbose > 1)
        cout << "minLambda: " << minlambda << "\t\t (lb = " << wcsp->
        getLb() << ", ub = " << wcsp->getUb() << ")" << endl;
}
示例#17
0
STATUS FtpData(FTP * con,char * command , char * file ,char * mode)
{
  struct sockaddr_in data,from;
  register struct hostent *host;
  FtpString hostname;
  int NewSocket,Accepted_Socket,len=sizeof(data),one=1,fromlen=sizeof(from),i;
  char *a,*b;

  FREE(data);
  FREE(from);
  
  if ( gethostname( hostname , sizeof hostname ) == -1 )
    return EXIT(con,QUIT);
  
  if ((host=(struct hostent *)gethostbyname(hostname))==0)
    return EXIT(con,QUIT);
  
  data.sin_family = host -> h_addrtype;
  
  bcopy(host-> h_addr_list[0],(char *)&data.sin_addr,host->h_length);
		
  if ((NewSocket = socket ( AF_INET  , SOCK_STREAM , 0 ))<0) {
	fprintf( stderr, "socket() failed in FtpData: %s\n", strerror( errno ) );

    return EXIT(con,QUIT);
  }

	if ( setsockopt ( NewSocket , SOL_SOCKET , SO_REUSEADDR , (char *)&one , sizeof(one) ) < 0 ) {
		fprintf( stderr, "setsockopt() failed in FtpData: %s\n", strerror( errno ) );
		close(NewSocket);
		return EXIT ( con,QUIT );
	}

	data.sin_port = 0 ;

	if ( bind ( NewSocket , (struct sockaddr*) &data , sizeof data ) < 0 ) {
		fprintf( stderr, "bind() failed in FtpData: %s\n", strerror( errno ) );
		close(NewSocket);
		return EXIT(con,QUIT);
	}

	if ( getsockname ( NewSocket , (struct sockaddr*) &data , (socklen_t *) &len ) < 0 ) {
		fprintf( stderr, "bind() failed in FtpData: %s\n", strerror( errno ) );
		close(NewSocket);
		return EXIT(con,QUIT);
	}
  
	if ( listen ( NewSocket , 1 ) < 0 ) {
		fprintf( stderr, "listen() failed in FtpData: %s\n", strerror( errno ) );
		close(NewSocket);
		return EXIT(con,QUIT);
	}

	a = ( char * ) & data.sin_addr;
	b = ( char * ) & data.sin_port;

	FtpAssert(con,FtpPort(con,CUT(a[0]),CUT(a[1]),CUT(a[2]),CUT(a[3]),CUT(b[0]),CUT(b[1])));

	if ( con -> seek != 0) {
		if ((i = FtpCommand ( con, "REST %d" , con -> seek , 0, EOF)) != 350 ) {
			close(NewSocket);
			return -i;
		}
	}
  
	FtpAssert(con, i=FtpCommand ( con , command , file , 200, 120 , 150 , 125 , 250 , EOF ));
  
	if (( Accepted_Socket = accept (NewSocket , (struct sockaddr *)&from , (socklen_t *) &fromlen )) < 0) {
		fprintf( stderr, "accept() failed in FtpData: %s\n", strerror( errno ) );
		close(NewSocket);
		return EXIT(con,QUIT);
	}

	close(NewSocket);

	FTPDATA(con) = winsock_fdopen(Accepted_Socket, "r+");

	return i;
}
示例#18
0
pair<Cost, Cost> Solver::recursiveSolve(Cluster* cluster, Cost lbgood, Cost cub)
{
    if (ToulBar2::verbose >= 1)
        cout << "[" << Store::getDepth() << "] recursive solve     cluster: " << cluster->getId() << "     clb: " << lbgood << "     cub: " << cub << "     clb0: " << cluster->getLb() << "     wcsp->lb: " << wcsp->getLb() << "     wcsp->ub: " << wcsp->getUb() << endl;
    assert(lbgood <= cub);
    TreeDecomposition* td = wcsp->getTreeDec();
    int varIndex = -1;
    if (ToulBar2::Static_variable_ordering)
        varIndex = getNextUnassignedVar(cluster);
    else if (ToulBar2::weightedDegree && ToulBar2::lastConflict)
        varIndex = ((ToulBar2::restart > 0) ? getVarMinDomainDivMaxWeightedDegreeLastConflictRandomized(cluster) : getVarMinDomainDivMaxWeightedDegreeLastConflict(cluster));
    else if (ToulBar2::lastConflict)
        varIndex = ((ToulBar2::restart > 0) ? getVarMinDomainDivMaxDegreeLastConflictRandomized(cluster) : getVarMinDomainDivMaxDegreeLastConflict(cluster));
    else if (ToulBar2::weightedDegree)
        varIndex = ((ToulBar2::restart > 0) ? getVarMinDomainDivMaxWeightedDegreeRandomized(cluster) : getVarMinDomainDivMaxWeightedDegree(cluster));
    else
        varIndex = ((ToulBar2::restart > 0) ? getVarMinDomainDivMaxDegreeRandomized(cluster) : getVarMinDomainDivMaxDegree(cluster));

    if (varIndex < 0) {
        // Current cluster is completely assigned
        Cost clb = wcsp->getLb();
        assert(clb <= cub);
        Cost csol = clb;

        for (TClusters::iterator iter = cluster->beginSortedEdges(); clb < cub && iter != cluster->endSortedEdges();) {
            // Solves each cluster son with local lower and upper bounds
            Cluster* c = *iter;
            ++iter;
            Cost lbSon = MIN_COST;
            Cost ubSon = MAX_COST;
            bool good = false;
            if (!c->isActive()) {
                c->reactivate();
                c->nogoodGet(lbSon, ubSon, &c->open);
                good = true;
            } else {
                lbSon = c->getLbRec();
                ubSon = c->getUb();
#ifndef NDEBUG
                Cost dummylb = -MAX_COST;
                Cost tmpub = -MAX_COST;
                c->nogoodGet(dummylb, tmpub, &c->open);
                assert(tmpub == ubSon);
#endif
            }
            if (ToulBar2::verbose >= 2)
                cout << "lbson: " << lbSon << " ubson: " << ubSon << " lbgood:" << lbgood << " clb: " << clb << " csol: " << csol << " cub: " << cub << " cluster->lb: " << c->getLbRec() << endl;
            if (lbSon < ubSon) { // we do not have an optimality proof
                if (clb <= lbgood || (csol < MAX_COST && ubSon >= cub - csol + lbSon)) { // we do not know a good enough son's solution or the currently reconstructed father's solution is not working or the currently reconstructed father's lower bound is not increasing
                    bool csolution = (csol < MAX_COST && ubSon < cub - csol + lbSon);
                    assert(!csolution || ubSon < cub - clb + lbSon);
                    ubSon = MIN(ubSon, cub - clb + lbSon);
                    td->setCurrentCluster(c);
                    wcsp->setUb(ubSon);
                    wcsp->setLb((good) ? c->getLbRec() : lbSon);
                    try {
                        Store::store();
                        wcsp->enforceUb();
                        wcsp->propagate();
                        Cost bestlb = MAX(wcsp->getLb(), lbSon);
                        if (csol < MAX_COST && iter == cluster->endSortedEdges())
                            bestlb = MAX(bestlb, lbgood - csol + lbSon); // simple trick to provide a better initial lower bound for the last son
                        if (ToulBar2::btdMode >= 2) {
                            Cost rds = td->getLbRecRDS();
                            bestlb = MAX(bestlb, rds);
                            if (CUT(bestlb, ubSon))
                                THROWCONTRADICTION;
                        }
                        pair<Cost, Cost> res = hybridSolve(c, bestlb, ubSon);
                        assert(res.first >= bestlb && res.second <= ubSon);
                        c->nogoodRec(res.first, ((res.second < ubSon) ? res.second : MAX_COST), &c->open);
                        clb += res.first - lbSon;
                        if (csol < MAX_COST) {
                            if (res.second < ubSon || csolution)
                                csol += res.second - lbSon;
                            else
                                csol = MAX_COST;
                        }
                    } catch (Contradiction) {
                        wcsp->whenContradiction();
                        c->nogoodRec(ubSon, MAX_COST, &c->open);
                        clb += ubSon - lbSon;
                        if (csolution)
                            csol += ubSon - lbSon;
                        else
                            csol = MAX_COST;
                    }
                    Store::restore();
                } else {
                    if (csol < MAX_COST) {
                        assert(ubSon < MAX_COST);
                        csol += ubSon - lbSon;
                    }
                }
            }
        }
        assert(csol >= clb);
        if (csol < cub) {
            // A new solution has been found for the current cluster
            cub = csol;
            cluster->solutionRec(csol);
            if (cluster == td->getRoot() || cluster == td->getRootRDS()) {
                if (ToulBar2::verbose >= 0 || ToulBar2::showSolutions) {
                    if (!ToulBar2::bayesian)
                        cout << "New solution: " << std::setprecision(ToulBar2::decimalPoint) << wcsp->Cost2ADCost(csol) << std::setprecision(DECIMAL_POINT) << " (" << nbBacktracks << " backtracks, " << nbNodes << " nodes, depth " << Store::getDepth() << ")" << endl;
                    else
                        cout << "New solution: " << csol << " energy: " << -(wcsp->Cost2LogProb(csol) + ToulBar2::markov_log) << " prob: " << std::scientific << wcsp->Cost2Prob(csol) * Exp(ToulBar2::markov_log) << std::fixed << " (" << nbBacktracks << " backtracks, " << nbNodes << " nodes, depth " << Store::getDepth() << ")" << endl;
                }
                if (cluster == td->getRoot())
                    td->newSolution(csol);
                else {
                    assert(cluster == td->getRootRDS());
                    // Remember current solution for value ordering heuristic
                    wcsp->restoreSolution(cluster);
                    TAssign a;
                    cluster->getSolution(a);
                    if (ToulBar2::showSolutions) {
                        TAssign::iterator it = a.begin();
                        while (it != a.end()) {
                            Value v = it->second;
                            cout << it->first << ":" << v << " ";
                            ++it;
                        }
                        cout << endl;
                    }
                }
            }
        }
        Cost bestlb = MAX(lbgood, clb);
        if (ToulBar2::verbose >= 1)
            cout << "[" << Store::getDepth() << "] C" << cluster->getId() << " return " << bestlb << " " << cub << endl;
        assert(bestlb <= cub);
        if (ToulBar2::hbfs && bestlb < cub) { // keep current node in open list instead of closing it!
            if (cluster->getNbVars() > 0) {
                int varid = *cluster->getVars().begin();
                assert(wcsp->assigned(varid));
                cluster->cp->addChoicePoint(CP_ASSIGN, varid, wcsp->getValue(varid), true); // dummy additional choice point to avoid the reversal of the last effective choice point for this open node
            }
#ifndef NDEBUG
            OpenList* prevopen = cluster->open;
            Cost tmplb = MIN_COST;
            Cost tmpub = MAX_COST;
            Cost tmpclusterub = cluster->getUb();
            assert(cluster == wcsp->getTreeDec()->getRoot() || cluster->nogoodGet(tmplb, tmpub, &cluster->open)); // warning! it can destroy cluster->ub
            cluster->setUb(tmpclusterub);
            assert(prevopen == cluster->open);
#endif
            addOpenNode(*(cluster->cp), *(cluster->open), bestlb, cluster->getCurrentDelta()); // reinsert as a new open node
            cluster->hbfsLimit = cluster->nbBacktracks; // and stop current visited node
            bestlb = cub;
        }
        return make_pair(bestlb, cub);
    } else {
        // Enumerates cluster proper variables
        *((StoreCost*)searchSize) += ((Cost)(10e6 * Log(wcsp->getDomainSize(varIndex))));
        pair<Cost, Cost> res = make_pair(MIN_COST, MAX_COST);
        if (wcsp->enumerated(varIndex)) {
            assert(wcsp->canbe(varIndex, wcsp->getSupport(varIndex)));
            // Reuse last solution found if available
            Value bestval = ((ToulBar2::verifyOpt) ? (wcsp->getSup(varIndex) + 1) : wcsp->getBestValue(varIndex));
            res = binaryChoicePoint(cluster, lbgood, cub, varIndex, (wcsp->canbe(varIndex, bestval)) ? bestval : wcsp->getSupport(varIndex));
        } else {
            res = binaryChoicePoint(cluster, lbgood, cub, varIndex, wcsp->getInf(varIndex));
        }
        if (ToulBar2::verbose >= 1)
            cout << "[" << Store::getDepth() << "] C" << cluster->getId() << " return " << res.first << " " << res.second << endl;
        assert(res.first >= lbgood);
        assert(res.second <= cub);
        assert(res.first <= res.second);
        return res;
    }
}
示例#19
0
BigInteger Solver::binaryChoicePointSBTD(Cluster* cluster, int varIndex, Value value)
{
    if (ToulBar2::interrupted)
        throw TimeOut();
    Cost cub = 1;
    Cost lbgood = 0;
    BigInteger nbSol = 0, nb = 0;
    assert(wcsp->unassigned(varIndex));
    assert(wcsp->canbe(varIndex, value));
    bool dichotomic = (ToulBar2::dichotomicBranching && ToulBar2::dichotomicBranchingSize < wcsp->getDomainSize(varIndex));
    Value middle = value;
    bool increasing = true;
    if (dichotomic) {
        middle = (wcsp->getInf(varIndex) + wcsp->getSup(varIndex)) / 2;
        if (value <= middle)
            increasing = true;
        else
            increasing = false;
    }
    try {
        Store::store();
        assert(wcsp->getTreeDec()->getCurrentCluster() == cluster);

        wcsp->setUb(cub);
        if (CUT(lbgood, cub))
            THROWCONTRADICTION;
        lastConflictVar = varIndex;
        if (dichotomic) {
            if (increasing)
                decrease(varIndex, middle);
            else
                increase(varIndex, middle + 1);
        } else
            assign(varIndex, value);
        lastConflictVar = -1;
        nb = sharpBTD(cluster);
        nbSol += nb;
    } catch (Contradiction) {
        wcsp->whenContradiction();
    }
    Store::restore();
    nbBacktracks++;
    if (ToulBar2::restart > 0 && nbBacktracks > nbBacktracksLimit)
        throw NbBacktracksOut();
#ifdef OPENMPI
    if (ToulBar2::vnsParallel && ((nbBacktracks % 128) == 0) && MPI_interrupted())
        throw TimeOut();
#endif
    try {
        Store::store();
        assert(wcsp->getTreeDec()->getCurrentCluster() == cluster);
        //		assert(wcsp->getLb() == cluster->getLbRec());
        wcsp->setUb(cub);
        if (CUT(lbgood, cub))
            THROWCONTRADICTION;
        if (dichotomic) {
            if (increasing)
                increase(varIndex, middle + 1);
            else
                decrease(varIndex, middle);
        } else
            remove(varIndex, value);

        nb = sharpBTD(cluster);
        nbSol += nb;
    } catch (Contradiction) {
        wcsp->whenContradiction();
    }
    Store::restore();
    return nbSol;
}
示例#20
0
pair<Cost, Cost> Solver::binaryChoicePoint(Cluster* cluster, Cost lbgood, Cost cub, int varIndex, Value value)
{
    assert(lbgood < cub);
    if (ToulBar2::interrupted)
        throw TimeOut();
    Cost clb = cub;
    TreeDecomposition* td = wcsp->getTreeDec();
    assert(wcsp->unassigned(varIndex));
    assert(wcsp->canbe(varIndex, value));
    bool dichotomic = (ToulBar2::dichotomicBranching && ToulBar2::dichotomicBranchingSize < wcsp->getDomainSize(varIndex));
    Value middle = value;
    bool increasing = true;
    if (dichotomic) {
        middle = (wcsp->getInf(varIndex) + wcsp->getSup(varIndex)) / 2;
        if (value <= middle)
            increasing = true;
        else
            increasing = false;
    }
    try {
        Store::store();
        assert(td->getCurrentCluster() == cluster);
        assert(wcsp->getLb() == cluster->getLbRec());
        wcsp->setUb(cub);
        Cost bestlb = lbgood;
        if (CUT(bestlb, cub))
            THROWCONTRADICTION;
        if (ToulBar2::btdMode >= 2) {
            Cost rds = td->getLbRecRDS();
            bestlb = MAX(bestlb, rds);
            if (CUT(bestlb, cub))
                THROWCONTRADICTION;
        }
        lastConflictVar = varIndex;
        if (dichotomic) {
            if (increasing)
                decrease(varIndex, middle);
            else
                increase(varIndex, middle + 1);
        } else
            assign(varIndex, value);
        lastConflictVar = -1;
        bestlb = MAX(bestlb, wcsp->getLb());
        pair<Cost, Cost> res = recursiveSolve(cluster, bestlb, cub);
        clb = MIN(res.first, clb);
        cub = MIN(res.second, cub);
    } catch (Contradiction) {
        wcsp->whenContradiction();
    }
    Store::restore();
    nbBacktracks++;
    if (ToulBar2::restart > 0 && nbBacktracks > nbBacktracksLimit)
        throw NbBacktracksOut();
#ifdef OPENMPI
    if (ToulBar2::vnsParallel && ((nbBacktracks % 128) == 0) && MPI_interrupted())
        throw TimeOut();
#endif
    cluster->nbBacktracks++;
    try {
        Store::store();
        assert(wcsp->getTreeDec()->getCurrentCluster() == cluster);
        assert(wcsp->getLb() == cluster->getLbRec());
        wcsp->setUb(cub);
        Cost bestlb = lbgood;
        if (CUT(bestlb, cub))
            THROWCONTRADICTION;
        if (ToulBar2::btdMode >= 2) {
            Cost rds = td->getLbRecRDS();
            bestlb = MAX(bestlb, rds);
            if (CUT(bestlb, cub))
                THROWCONTRADICTION;
        }
        if (dichotomic) {
            if (increasing)
                increase(varIndex, middle + 1, cluster->nbBacktracks >= cluster->hbfsLimit || nbBacktracks >= cluster->hbfsGlobalLimit);
            else
                decrease(varIndex, middle, cluster->nbBacktracks >= cluster->hbfsLimit || nbBacktracks >= cluster->hbfsGlobalLimit);
        } else
            remove(varIndex, value, cluster->nbBacktracks >= cluster->hbfsLimit || nbBacktracks >= cluster->hbfsGlobalLimit);
        bestlb = MAX(bestlb, wcsp->getLb());
        if (!ToulBar2::hbfs && cluster == td->getRoot() && initialDepth + 1 == Store::getDepth()) {
            initialDepth++;
            showGap(bestlb, cub);
        };
        if (cluster->nbBacktracks >= cluster->hbfsLimit || nbBacktracks >= cluster->hbfsGlobalLimit) {
            addOpenNode(*(cluster->cp), *(cluster->open), bestlb, cluster->getCurrentDelta());
        } else {
            pair<Cost, Cost> res = recursiveSolve(cluster, bestlb, cub);
            clb = MIN(res.first, clb);
            cub = MIN(res.second, cub);
        }
    } catch (Contradiction) {
        wcsp->whenContradiction();
    }
    Store::restore();
    assert(lbgood <= clb);
    assert(clb <= cub);
    return make_pair(clb, cub);
}
示例#21
0
int main(int argc, char** argv)
{
/*
	FRONT & BACK
                        v--- finger_size_x
           ###   ###   ###   ###   ###   ###   ###   ###   ###
	#########################################################
      #######################frame_width###########################
      ####    #     #     #    #                               ####
        ##    #     #     #    #                    ^          ##
        ##    #     #     #    #                    |num_      ##
      #########front_mid_width############# . . .   |front_    #### <-- finger_size_y
      ####    #     #     #    #    . . .           |holes_y   ####
       ###    #     #     #    #                    v          ##
        ##    #     #     #         hole at every cell (y[0])  ##
      ####    #     #            ...  <----------->            ####
      #############################################################
        #########################################################
           ###   ###   ###   ###   ###   ###   ###   ###   ###

*/


	if(argc < 5)
	{
		printf("Usage: cnc_gen <outfile_prefix> <y1> <y2> <x> <y cellgap|offset> <x scaling factor> <gap1> <gap2> <gap3> <gap4>\n");
		printf("Ex.: cnc_gen out 4 3 11\n");
                printf("      ---- X ---->       \n");
		printf("__-_-_-_-_-_4_-_-_-_-_-__\n");
		printf("| O   O   O   O   O   O |\n");
		printf("|   O   O   O   O   O   |\n");
		printf("| O   O   O   O   O   O |\n");
		printf("1   O   O   O   O   O   3\n");
		printf("| O   O   O   O   O   O |\n");
		printf("|   O   O   O   O   O   |\n");
		printf("| O   O   O   O   O   O |\n");
		printf("------------2------------\n");
		return 1;
	}

	fullcut_z = z_at_surface - thickness - cut_through_base;
	cellgap = cell_to_cell-cell;


	ys[0] = atoi(argv[2]);
	if(ys[0] < 1 || ys[0] > 100) { printf("Invalid y1\n"); return 1;}

	ys[1] = atoi(argv[3]);
	if(ys[1] < 1 || ys[1] > 100) { printf("Invalid y2\n"); return 1;}
	if(ys[1] < ys[0]-1 || ys[1] > ys[0]) { printf("y2 must be y1-1 or y1\n"); return 1;}

	x = atoi(argv[4]);
	if(x < 1 || x > 100) { printf("Invalid x\n"); return 1;}

	char mainfilename[1000];
	char coverfilename[1000];
	sprintf(mainfilename, "%s_main.ngc", argv[1]);
	sprintf(coverfilename, "%s_cover.ngc", argv[1]);

	FILE* gfile = fopen(mainfilename, "wb");
	if(!gfile)
	{
		printf("Error opening file %s\n", mainfilename);
		return 1;
	}

	FILE* coverfile;

	if(do_covers)
	{
		coverfile = fopen(coverfilename, "wb");
		if(!coverfile)
		{
			printf("Error opening file %s\n", coverfilename);
			return 1;
		}
	}

	float y_step = cell + cellgap;
	float x_step = sqrt(  (3.0*(cell/2.0)*(cell/2.0)) + (2.0*(cell/2.0)*cellgap)  ) * 1.05 * spacing_trim; // todo: fix math...

	printf("y_step = %f, x_step = %f\n", y_step, x_step);

	fprintf(gfile, "(");
	for(int i = 0; i < 4; i++)
	{
		fprintf(gfile, " %s ", argv[i]);
	}
	fprintf(gfile, ")\n");

	fprintf(gfile, "G21\n");
	fprintf(gfile, "G90\n"); // absolute coords.
//	fprintf(gfile, "G61\n"); // forces complete stop in corners, resulting in less rounding of corners.

	fprintf(gfile, "G00 Z%.2f\n", z_at_idle);

	if(do_covers)
	{
		fprintf(coverfile, "G21\n");
		fprintf(coverfile, "G61\n");
		COVER_UNCUT();
		fprintf(coverfile, "G00 F%.2f\n", cover_feedrate);
		fprintf(coverfile, "M07 (air on)\n");
		delay(coverfile, 5.0);

	}

	float front_origin_x = 10.0;
	float front_origin_y = 10.0;
	float side_origin_x = 10.0;
	float side_origin_y = 10.0;

	float cover_origin_x = 10.0;
	float cover_origin_y = 10.0;

	float origin_x = 10.0+thickness;
	float origin_y = 10.0+thickness;

	if(do_fronts)
	{
		origin_x += cell_length + part_separation;
		side_origin_x = origin_x;
	}

	if(do_sides == 1)
	{
		if(side_at_back)
		{
			side_origin_x = origin_x + wallgaps[0] + x_step*(x-1) + cell + wallgaps[2] + part_separation
				+ thickness*2.0;
		}
		else
		{
			origin_y += cell_length + part_separation + (do_covers?(cover_thickness*2.0):0.0);
			front_origin_y = origin_y;
		}
	}

	for(int curx = 0; curx < x; curx++)
	{
		int y = ys[curx%2];
		float y_offset = (curx%2)?(y_step/2.0):(0.0);
		for(int cury = 0; cury < y; cury++)
		{

			float mid_x = origin_x + wallgaps[0] + x_step*curx + cell/2.0;
			float mid_y = origin_y + wallgaps[1] + y_step*cury + cell/2.0 + y_offset;

			fprintf(gfile, "(WELDPOINT %u;%u;%.2f;%.2f)\n", curx, cury, mid_x-origin_x, mid_y-origin_y);
			do_cellhole(gfile, mid_x, mid_y);

/*
			// Do end bms bonusholes:
			if(((curx == 0) || (curx == x-1)) && (cury == y-1) && end_bonusholes > 0.01)
			{
				float bonushole_midx = mid_x;
				if(curx == 0) bonushole_midx -= cell/2.0; else bonushole_midx += cell/2.0;

				float bonushole_midy = origin_y + wallgaps[1] + y_step*(ys[0]-1) + cell/2.0;
				float shift = cell/2.0 + end_bonusholes/2.0 + end_bonusholes_dist;
				bonushole_midy += shift;
				float bonushole_startx = bonushole_midx - end_bonusholes/2.0;
				float bonushole_startx_trimmed = bonushole_startx + toolsize;
				float bonushole_starty_trimmed = bonushole_midy;

				float bonushole_offset_i = end_bonusholes/2.0 - toolsize;
				float bonushole_offset_j = 0.0;

				fprintf(gfile, "G00 X%.2f Y%.2f\n", bonushole_startx_trimmed, bonushole_starty_trimmed);
				CUT();
				fprintf(gfile, "G02 X%.2f Y%.2f I%.2f J%.2f\n", bonushole_startx_trimmed, bonushole_starty_trimmed,
					bonushole_offset_i, bonushole_offset_j);

				UNCUT();
				delay(gfile, delay_per_cell*0.25);


			}

			// Do cell bms bonusholes:
			if((curx%2 == 0) && ((cury == y-1)) && bonushole > 0.01)
			{
				float bonushole_midx = mid_x;
//					(
//					(2.0*(origin_x + wallgaps[0] + x_step*(curx-1) + cell/2.0))+
//					(1.0*(origin_x + wallgaps[0] + x_step*curx     + cell/2.0))
//					)/3.0;
				float bonushole_midy = mid_y;
				float shift = cell/2.0 + bonushole/2.0 + bonushole_dist;
				if(cury == 0) bonushole_midy -= shift; else bonushole_midy += shift;
				float bonushole_startx = bonushole_midx - bonushole/2.0;
				float bonushole_startx_trimmed = bonushole_startx + toolsize;
				float bonushole_starty_trimmed = bonushole_midy;

				float bonushole_offset_i = bonushole/2.0 - toolsize;
				float bonushole_offset_j = 0.0;

				fprintf(gfile, "G00 X%.2f Y%.2f\n", bonushole_startx_trimmed, bonushole_starty_trimmed);
				CUT();
				fprintf(gfile, "G02 X%.2f Y%.2f I%.2f J%.2f\n", bonushole_startx_trimmed, bonushole_starty_trimmed,
					bonushole_offset_i, bonushole_offset_j);

				UNCUT();
				delay(gfile, delay_per_cell*0.25);
			}

*/
//			delay(gfile, delay_per_cell);

		}
	}

	float outline[4][2];
	float side_outline[2][2];
	float cover_outline[4][2];
	outline[0][X] = origin_x;
	outline[0][Y] = origin_y;
	outline[1][X] = origin_x + wallgaps[0] + x_step*(x-1) + cell + wallgaps[2];
	outline[1][Y] = outline[0][Y];
	outline[2][X] = outline[1][X];
	outline[2][Y] = origin_y + wallgaps[1] + y_step*(ys[0]-1) + cell + wallgaps[3];
	if(ys[1] == ys[0])
		outline[2][Y] += y_step/2.0;
	outline[3][X] = origin_x;
	outline[3][Y] = outline[2][Y];

	side_outline[0][X] = side_origin_x;
	side_outline[0][Y] = side_origin_y;
	side_outline[1][X] = side_origin_x + wallgaps[0] + x_step*(x-1) + cell + wallgaps[2];
	side_outline[1][Y] = side_outline[0][Y];

	cover_outline[0][X] = cover_origin_x;
	cover_outline[0][Y] = cover_origin_y;
	cover_outline[1][X] = cover_origin_x + wallgaps[0] + x_step*(x-1) + cell + wallgaps[2];
	cover_outline[1][Y] = cover_outline[0][Y];
	cover_outline[2][X] = cover_outline[1][X];
	cover_outline[2][Y] = cover_origin_y + wallgaps[1] + y_step*(ys[0]-1) + cell + wallgaps[3];
	if(ys[1] == ys[0])
		cover_outline[2][Y] += y_step/2.0;
	cover_outline[3][X] = cover_outline[0][X];
	cover_outline[3][Y] = cover_outline[2][Y];

	fprintf(gfile, "G00 X%.2f Y%.2f (ALIGNPOINT 0;0;%.2f;%.2f)\n", outline[0][X]-toolsize, outline[0][Y]-toolsize,
		outline[0][X]-(do_fronts?thickness:0.0), outline[0][Y]-(do_sides?thickness:0.0));

	if(do_covers)
	{
		fprintf(coverfile, "G00 X%.2f Y%.2f\n", cover_outline[0][X]-thickness-cover_toolsize, cover_outline[0][Y]-cover_toolsize);
		COVER_CUT();
	}

	// horizontal bottom side
	if(do_sides)
	{
		// Finger cut
		for(int curx = 0; curx < x; curx++)
		{
			float finger_start_x = origin_x + wallgaps[0] + x_step*curx + cell/2.0 - finger_size_x/2.0;
			float finger_end_x = finger_start_x + finger_size_x;

			float cfinger_start_x = cover_origin_x + wallgaps[0] + x_step*curx + cell/2.0 - finger_size_x/2.0;
			float cfinger_end_x = cfinger_start_x + finger_size_x;

			fprintf(gfile, "G01 X%.2f Y%.2f Z%.2f F%.2f\n", finger_start_x-toolsize, outline[0][Y]-toolsize, fullcut_z, feedrate);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", finger_start_x-toolsize, outline[0][Y]
				-thickness-toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", finger_end_x+toolsize, outline[0][Y]
				-thickness-toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", finger_end_x+toolsize, outline[0][Y]-toolsize);

			if(do_covers)
			{
				fprintf(coverfile, "G01 X%.2f Y%.2f F%.2f\n", cfinger_start_x-cover_toolsize, cover_outline[0][Y]-cover_toolsize, cover_feedrate);
				fprintf(coverfile, "G01 X%.2f Y%.2f\n", cfinger_start_x-cover_toolsize, cover_outline[0][Y]
					-thickness-cover_toolsize);
				fprintf(coverfile, "G01 X%.2f Y%.2f\n", cfinger_end_x+cover_toolsize, cover_outline[0][Y]
					-thickness-cover_toolsize);
				fprintf(coverfile, "G01 X%.2f Y%.2f\n", cfinger_end_x+cover_toolsize, cover_outline[0][Y]-cover_toolsize);
			}

		}
	}

	fprintf(gfile, "G01 X%.2f Y%.2f (ALIGNPOINT 1;0;%.2f;%.2f)\n", outline[1][X]+toolsize, outline[1][Y]-toolsize,
		outline[1][X]+(do_fronts?thickness:0.0), outline[1][Y]-(do_sides?thickness:0.0));

	if(do_covers)
	{
		fprintf(coverfile, "G01 X%.2f Y%.2f F%.2f\n", cover_outline[1][X]+thickness+cover_toolsize, cover_outline[1][Y]-cover_toolsize, cover_feedrate);

	}

	if(do_covers)
	{
		COVER_UNCUT();
		delay(coverfile, cover_delay_per_cell*x);
		COVER_CUT();
	}


	// vertical right side
	if(do_fronts)
	{
		// Finger cut
		for(int cury = 0; cury < ys[0]; cury++)
		{
			float finger_start_y = origin_y + wallgaps[1] + y_step*cury + cell/2.0 - finger_size_y/2.0;
			float finger_end_y = finger_start_y + finger_size_y;
			float cfinger_start_y = cover_origin_y + wallgaps[1] + y_step*cury + cell/2.0 - finger_size_y/2.0;
			float cfinger_end_y = cfinger_start_y + finger_size_y;
			fprintf(gfile, "G01 X%.2f Y%.2f\n", outline[1][X]+toolsize, finger_start_y-toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", outline[1][X]+thickness+toolsize, finger_start_y-toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", outline[1][X]+thickness+toolsize, finger_end_y+toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", outline[1][X]+toolsize, finger_end_y+toolsize);

/*
			if(do_covers)
			{
				fprintf(coverfile, "G01 X%.2f Y%.2f\n", cover_outline[1][X]+cover_toolsize, cfinger_start_y-cover_toolsize);
				fprintf(coverfile, "G01 X%.2f Y%.2f\n", cover_outline[1][X]+thickness+cover_toolsize, cfinger_start_y-cover_toolsize);
				fprintf(coverfile, "G01 X%.2f Y%.2f\n", cover_outline[1][X]+thickness+cover_toolsize, cfinger_end_y+cover_toolsize);
				fprintf(coverfile, "G01 X%.2f Y%.2f\n", cover_outline[1][X]+cover_toolsize, cfinger_end_y+cover_toolsize);

			}
*/
		}
	}

	fprintf(gfile, "G01 X%.2f Y%.2f (ALIGNPOINT 1;1;%.2f;%.2f)\n", outline[2][X]+toolsize, outline[2][Y]+toolsize,
		outline[2][X]+(do_fronts?thickness:0.0), outline[2][Y]+(do_sides?thickness:0.0));

	if(do_covers)
	{
		fprintf(coverfile, "G01 X%.2f Y%.2f\n", cover_outline[2][X]+thickness+cover_toolsize, cover_outline[2][Y]+cover_toolsize);
	}

	if(do_covers)
	{
		COVER_UNCUT();
		delay(coverfile, 0.7*cover_delay_per_cell*ys[0]);
		COVER_CUT();
	}



	// horizontal top side

	if(do_sides)
	{
		// Finger cut
		for(int curx = x-1; curx >= 0; curx--)
		{
			float finger_end_x = origin_x + wallgaps[0] + x_step*curx + cell/2.0 - finger_size_x/2.0;
			float finger_start_x = finger_end_x + finger_size_x;
			float cfinger_end_x = cover_origin_x + wallgaps[0] + x_step*curx + cell/2.0 - finger_size_x/2.0;
			float cfinger_start_x = cfinger_end_x + finger_size_x;

			fprintf(gfile, "G01 X%.2f Y%.2f\n", finger_start_x+toolsize, outline[2][Y]+toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", finger_start_x+toolsize, outline[2][Y]+thickness+toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", finger_end_x-toolsize, outline[2][Y]+thickness+toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", finger_end_x-toolsize, outline[2][Y]+toolsize);

			if(do_covers)
			{
				fprintf(coverfile, "G01 X%.2f Y%.2f\n", cfinger_start_x+cover_toolsize, cover_outline[2][Y]+cover_toolsize);
				fprintf(coverfile, "G01 X%.2f Y%.2f\n", cfinger_start_x+cover_toolsize, cover_outline[2][Y]+thickness+cover_toolsize);
				fprintf(coverfile, "G01 X%.2f Y%.2f\n", cfinger_end_x-cover_toolsize, cover_outline[2][Y]+thickness+cover_toolsize);
				fprintf(coverfile, "G01 X%.2f Y%.2f\n", cfinger_end_x-cover_toolsize, cover_outline[2][Y]+cover_toolsize);
			}
		}
	}

	fprintf(gfile, "G01 X%.2f Y%.2f (ALIGNPOINT 0;1;%.2f;%.2f)\n", outline[3][X]-toolsize, outline[3][Y]+toolsize,
		outline[3][X]-(do_fronts?thickness:0.0), outline[3][Y]+(do_sides?thickness:0.0));

	if(do_covers)
	{
		fprintf(coverfile, "G01 X%.2f Y%.2f\n", cover_outline[3][X]-thickness-cover_toolsize, cover_outline[3][Y]+cover_toolsize);
	}

	if(do_covers)
	{
		COVER_UNCUT();
		delay(coverfile, cover_delay_per_cell*x);
		COVER_CUT();
	}

	// Vertical left side

	if(do_fronts)
	{
		// Finger cut
		for(int cury = ys[0]-1; cury >=0; cury--)
		{
			float finger_end_y = origin_y + wallgaps[1] + y_step*cury + cell/2.0 - finger_size_y/2.0;
			float finger_start_y = finger_end_y + finger_size_y;
			float cfinger_end_y = cover_origin_y + wallgaps[1] + y_step*cury + cell/2.0 - finger_size_y/2.0;
			float cfinger_start_y = cfinger_end_y + finger_size_y;
			fprintf(gfile, "G01 X%.2f Y%.2f\n", outline[3][X]-toolsize, finger_start_y+toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", outline[3][X]-thickness-toolsize, finger_start_y+toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", outline[3][X]-thickness-toolsize, finger_end_y-toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", outline[3][X]-toolsize, finger_end_y-toolsize);

/*
			if(do_covers)
			{
				fprintf(coverfile, "G01 X%.2f Y%.2f\n", cover_outline[3][X]-cover_toolsize, cfinger_start_y+cover_toolsize);
				fprintf(coverfile, "G01 X%.2f Y%.2f\n", cover_outline[3][X]-thickness-cover_toolsize, cfinger_start_y+cover_toolsize);
				fprintf(coverfile, "G01 X%.2f Y%.2f\n", cover_outline[3][X]-thickness-cover_toolsize, cfinger_end_y-cover_toolsize);
				fprintf(coverfile, "G01 X%.2f Y%.2f\n", cover_outline[3][X]-cover_toolsize, cfinger_end_y-cover_toolsize);
			}
*/
		}

	}


	fprintf(gfile, "G01 X%.2f Y%.2f\n", outline[0][X]-toolsize, outline[0][Y]-toolsize);
	fprintf(gfile, "G01 Z%.2f\n", z_at_idle);

	if(do_covers)
	{
		fprintf(coverfile, "G01 X%.2f Y%.2f\n", cover_outline[0][X]-thickness-cover_toolsize, cover_outline[0][Y]-cover_toolsize);

	}

	if(do_covers)
	{
		COVER_UNCUT();
//		delay(coverfile, 0.7*cover_delay_per_cell*ys[0]);
	}



	printf("Main panel size without fingers: %.2f x %.2f\n", outline[1][X]-outline[0][X], outline[2][Y]-outline[1][Y]);
	printf("Total box size: %.2f x %.2f x %.2f\n", outline[1][X]-outline[0][X]+2.0*thickness, outline[2][Y]-outline[1][Y]+2.0*thickness, cell_length+2.0*cover_thickness);
	printf("Sheet needed: %.2f x %.2f\n", outline[1][X]-outline[0][X]+2.0*thickness+cell_length+part_separation, outline[2][Y]-outline[1][Y]+2.0*thickness+cell_length+2.0*cover_thickness+part_separation);
	if(do_covers)
		printf("Cover size with fingers (sheet needed): %.2f x %.2f\n", cover_outline[1][X]-cover_outline[0][X]+2.0*thickness, cover_outline[2][Y]-cover_outline[1][Y]+2.0*thickness);

/*

|||| thickness
c ||||  < 0.5 steps
e ||    ^ 1
l ||||  v step
l ||    ^ 1
l ||||  v step
e ||    ^ 1
n ||||  v step
|||| thickness

*/


	float side_front_finger_step = (cell_length - 2.0*thickness) / ((float)num_side_front_fingers-0.5);

	// Do side panel
	if(do_sides)
	{
		fprintf(gfile, "G00 X%.2f Y%.2f\n", side_outline[0][X]-toolsize, side_origin_y-(do_covers?cover_thickness:0.0)-toolsize);
		CUT();
		// Bottom horizontal
		for(int curx = 0; curx < x; curx++)
		{
			float finger_start_x = side_origin_x + wallgaps[0] + x_step*curx + cell/2.0 - finger_size_x/2.0;
			float finger_end_x = finger_start_x + finger_size_x;

			fprintf(gfile, "G01 X%.2f Y%.2f\n", finger_start_x+toolsize, side_origin_y-(do_covers?cover_thickness:0.0)-toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", finger_start_x+toolsize, side_origin_y+thickness-toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", finger_end_x-toolsize, side_origin_y+thickness-toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", finger_end_x-toolsize, side_origin_y-(do_covers?cover_thickness:0.0)-toolsize);
		}

		fprintf(gfile, "G01 X%.2f Y%.2f\n", side_outline[1][X]+toolsize, side_origin_y-(do_covers?cover_thickness:0.0)-toolsize);

		UNCUT();
		delay(gfile, delay_per_cell*x);
		CUT_PWR(vertical_power_mult);

		// Right vertical
		for(int cury = 0; cury < num_side_front_fingers; cury++)
		{
			float finger_start_y = side_origin_y + thickness +
				side_front_finger_step*cury;
			float finger_end_y = finger_start_y + side_front_finger_step/2.0;
			fprintf(gfile, "G01 X%.2f Y%.2f\n", side_outline[1][X]+toolsize, finger_start_y-toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", side_outline[1][X]+thickness+toolsize, finger_start_y-toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", side_outline[1][X]+thickness+toolsize, finger_end_y+toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", side_outline[1][X]+toolsize, finger_end_y+toolsize);
		}

		fprintf(gfile, "G01 X%.2f Y%.2f\n", side_outline[1][X]+toolsize, side_origin_y+cell_length+(do_covers?cover_thickness:0.0)+toolsize);

		UNCUT();
		delay(gfile, delay_per_cell*3);
		CUT();

		// Top horizontal
		for(int curx = x-1; curx >= 0; curx--)
		{
			float finger_end_x = side_origin_x + wallgaps[0] + x_step*curx + cell/2.0 - finger_size_x/2.0;
			float finger_start_x = finger_end_x + finger_size_x;

			fprintf(gfile, "G01 X%.2f Y%.2f\n", finger_start_x-toolsize, side_origin_y+cell_length+(do_covers?cover_thickness:0.0)+toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", finger_start_x-toolsize, side_origin_y+cell_length-thickness+toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", finger_end_x+toolsize, side_origin_y+cell_length-thickness+toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", finger_end_x+toolsize, side_origin_y+cell_length+(do_covers?cover_thickness:0.0)+toolsize);
		}

		fprintf(gfile, "G01 X%.2f Y%.2f\n", side_outline[0][X]-toolsize, side_origin_y+cell_length+(do_covers?cover_thickness:0.0)+toolsize);

		UNCUT();
		delay(gfile, delay_per_cell*x);
		CUT_PWR(vertical_power_mult);

		// Left vertical

		for(int cury = num_side_front_fingers-1; cury >= 0; cury--)
		{
			float finger_end_y = side_origin_y + thickness +
				side_front_finger_step*cury;
			float finger_start_y = finger_end_y + side_front_finger_step/2.0;
			fprintf(gfile, "G01 X%.2f Y%.2f\n", side_outline[0][X]-toolsize, finger_start_y+toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", side_outline[0][X]-thickness-toolsize, finger_start_y+toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", side_outline[0][X]-thickness-toolsize, finger_end_y-toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", side_outline[0][X]-toolsize, finger_end_y-toolsize);
		}

		fprintf(gfile, "G01 X%.2f Y%.2f\n", side_outline[0][X]-toolsize, side_origin_y-(do_covers?cover_thickness:0.0)-toolsize);

		UNCUT();
		delay(gfile, delay_per_cell*3);

		if(do_side_bonusholes)
		{
			for(int curx = 0; curx < x; curx++)
			{
				int y = ys[curx%2];
				float y_offset = (curx%2)?(y_step/2.0):(0.0);
				for(int cury = 0; cury < 2; cury++)
				{
					if(curx%2)
					{
						float bonushole_midx = side_origin_x + wallgaps[0] + x_step*curx + cell/2.0;
						float bonushole_midy = cury?
							(side_origin_y+cell_length-thickness-side_bonushole_dist):
							(side_origin_y+thickness+side_bonushole_dist);
						float bonushole_startx = bonushole_midx - side_bonushole_size/2.0;
						float bonushole_startx_trimmed = bonushole_startx + toolsize;
						float bonushole_starty_trimmed = bonushole_midy;

						float bonushole_offset_i = side_bonushole_size/2.0 - toolsize;
						float bonushole_offset_j = 0.0;

						fprintf(gfile, "G00 X%.2f Y%.2f\n", bonushole_startx_trimmed, bonushole_starty_trimmed);
						if(do_side_bonusholes == 2)
						{
							CUT_MARK();
						}
						else
						{
							CUT();
						}
						fprintf(gfile, "G02 X%.2f Y%.2f I%.2f J%.2f\n", bonushole_startx_trimmed, bonushole_starty_trimmed,
							bonushole_offset_i, bonushole_offset_j);
						UNCUT();
						if(do_side_bonusholes != 2)
						{
							delay(gfile, delay_per_cell*0.25);
						}
					}
				}
			}
		} // end do_side_bonusholes

	} // end do side panel

	// Do front panel
	if(do_fronts)
	{
		// Cut ventilation holes

		float fhole_width = (cell+cellgap) - front_mid_width;
		float fhole_hstep = (cell_length - 2.0*thickness - 2.0*front_y_frame_width)/((float)num_front_holes_y);
		float fhole_height = fhole_hstep-front_mid_width;

		for(int cury = 0; cury < ys[0]; cury++)
		{
			float fhole_start_y = origin_y + wallgaps[1] + y_step*cury + cell/2.0 - fhole_width/2.0;
			if(ys[0] == ys[1])
				fhole_start_y += (cell+cellgap)/4.0;

			float fhole_end_y = fhole_start_y + fhole_width;

			for(int curx = 0; curx < num_front_holes_y; curx++)
			{
				float fhole_start_x = front_origin_x + thickness + front_y_frame_width + fhole_hstep*curx
						+ front_mid_width/2.0;
				float fhole_end_x = fhole_start_x + fhole_height;

				fprintf(gfile, "G00 X%.2f Y%.2f\n", fhole_start_x+toolsize, fhole_start_y+toolsize);
				CUT();
				fprintf(gfile, "G01 X%.2f Y%.2f\n", fhole_end_x-toolsize, fhole_start_y+toolsize);
				fprintf(gfile, "G01 X%.2f Y%.2f\n", fhole_end_x-toolsize, fhole_end_y-toolsize);
				fprintf(gfile, "G01 X%.2f Y%.2f\n", fhole_start_x+toolsize, fhole_end_y-toolsize);
				fprintf(gfile, "G01 X%.2f Y%.2f\n", fhole_start_x+toolsize, fhole_start_y+toolsize);
				UNCUT();
				delay(gfile, delay_per_cell);

			}
		}


		// Left vertical (joins bottom main cell board)
		fprintf(gfile, "G00 X%.2f Y%.2f\n", front_origin_x-toolsize, outline[3][Y]+thickness+toolsize);
		CUT_PWR(vertical_power_mult);
		for(int cury = ys[0]-1; cury >=0; cury--)
		{
			float finger_end_y = origin_y + wallgaps[1] + y_step*cury + cell/2.0 - finger_size_y/2.0;
			float finger_start_y = finger_end_y + finger_size_y;
			fprintf(gfile, "G01 X%.2f Y%.2f\n", front_origin_x-toolsize, finger_start_y-toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", front_origin_x+thickness-toolsize, finger_start_y-toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", front_origin_x+thickness-toolsize, finger_end_y+toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", front_origin_x-toolsize, finger_end_y+toolsize);
		}

		fprintf(gfile, "G01 X%.2f Y%.2f\n", front_origin_x-toolsize, outline[0][Y]-thickness-toolsize);

		UNCUT();
		delay(gfile, delay_per_cell*ys[0]);
		CUT();

		// Bottom horizontal (joins to a side board)

		for(int curx = 0; curx < num_side_front_fingers; curx++)
		{
			float finger_start_x = front_origin_x + thickness +
				side_front_finger_step*curx;
			float finger_end_x = finger_start_x + side_front_finger_step/2.0;
			fprintf(gfile, "G01 X%.2f Y%.2f\n", finger_start_x+toolsize, outline[0][Y]-thickness-toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", finger_start_x+toolsize, outline[0][Y]-toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", finger_end_x-toolsize, outline[0][Y]-toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", finger_end_x-toolsize, outline[0][Y]-thickness-toolsize);
		}

		fprintf(gfile, "G01 X%.2f Y%.2f\n", front_origin_x+cell_length+toolsize, outline[0][Y]-thickness-toolsize);

		UNCUT();
		delay(gfile, delay_per_cell*3);
		CUT_PWR(vertical_power_mult);

		// Right vertical (joins to top main cell board)

		for(int cury = 0; cury < ys[0]; cury++)
		{
			float finger_start_y = origin_y + wallgaps[1] + y_step*cury + cell/2.0 - finger_size_y/2.0;
			float finger_end_y = finger_start_y + finger_size_y;
			fprintf(gfile, "G01 X%.2f Y%.2f\n", front_origin_x+cell_length+toolsize, finger_start_y+toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", front_origin_x+cell_length-thickness+toolsize, finger_start_y+toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", front_origin_x+cell_length-thickness+toolsize, finger_end_y-toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", front_origin_x+cell_length+toolsize, finger_end_y-toolsize);
		}

		fprintf(gfile, "G01 X%.2f Y%.2f\n", front_origin_x+cell_length+toolsize, outline[2][Y]+thickness+toolsize);

		UNCUT();
		delay(gfile, delay_per_cell*ys[0]);
		CUT();

		// Top horizontal (joins to another side board)

		for(int curx = num_side_front_fingers-1; curx >= 0; curx--)
		{
			float finger_end_x = front_origin_x + thickness +
				side_front_finger_step*curx;
			float finger_start_x = finger_end_x + side_front_finger_step/2.0;
			fprintf(gfile, "G01 X%.2f Y%.2f\n", finger_start_x-toolsize, outline[2][Y]+thickness+toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", finger_start_x-toolsize, outline[2][Y]+toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", finger_end_x+toolsize, outline[2][Y]+toolsize);
			fprintf(gfile, "G01 X%.2f Y%.2f\n", finger_end_x+toolsize, outline[2][Y]+thickness+toolsize);
		}

		fprintf(gfile, "G01 X%.2f Y%.2f\n", front_origin_x-toolsize, outline[3][Y]+thickness+toolsize);

		UNCUT();
//		delay(gfile, delay_per_cell*3);

	}

	fprintf(gfile, "G00 X%.2f Y%.2f\n", origin_x, origin_y);
	delay(gfile, 15.0);


	fprintf(gfile, "M2\n%%\n");
	fclose(gfile);

	if(do_covers)
	{
		fprintf(coverfile, "G00 X%.2f Y%.2f\n", cover_origin_x, cover_origin_y);
		delay(coverfile, 15.0);
		fprintf(coverfile, "M2\n%%\n");
		fclose(coverfile);
	}

	return 0;
}