Skip to content

Commit 4598061

Browse files
committed
Fixed infinite loop in training due to poor clipping of the table filler
1 parent 5bb0d89 commit 4598061

File tree

3 files changed

+54
-84
lines changed

3 files changed

+54
-84
lines changed

classify/float2int.cpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,12 @@ void Classify::ComputeIntFeatures(FEATURE_SET Features,
111111
for (Fid = 0; Fid < Features->NumFeatures; Fid++) {
112112
Feature = Features->Features[Fid];
113113

114-
IntFeatures[Fid].X = BucketFor (Feature->Params[PicoFeatX],
115-
X_SHIFT, INT_FEAT_RANGE);
116-
IntFeatures[Fid].Y = BucketFor (Feature->Params[PicoFeatY],
117-
YShift, INT_FEAT_RANGE);
118-
IntFeatures[Fid].Theta = CircBucketFor (Feature->Params[PicoFeatDir],
119-
ANGLE_SHIFT, INT_FEAT_RANGE);
114+
IntFeatures[Fid].X =
115+
Bucket8For(Feature->Params[PicoFeatX], X_SHIFT, INT_FEAT_RANGE);
116+
IntFeatures[Fid].Y =
117+
Bucket8For(Feature->Params[PicoFeatY], YShift, INT_FEAT_RANGE);
118+
IntFeatures[Fid].Theta = CircBucketFor(Feature->Params[PicoFeatDir],
119+
ANGLE_SHIFT, INT_FEAT_RANGE);
120120
IntFeatures[Fid].CP_misses = 0;
121121
}
122122
} /* ComputeIntFeatures */

classify/intproto.cpp

+45-76
Original file line numberDiff line numberDiff line change
@@ -439,52 +439,25 @@ void AddProtoToProtoPruner(PROTO Proto, int ProtoId,
439439

440440

441441
/*---------------------------------------------------------------------------*/
442-
int BucketFor(FLOAT32 Param, FLOAT32 Offset, int NumBuckets) {
443-
/*
444-
** Parameters:
445-
** Param parameter value to map into a bucket number
446-
** Offset amount to shift param before mapping it
447-
** NumBuckets number of buckets to map param into
448-
** Globals: none
449-
** Operation: This routine maps a parameter value into a bucket between
450-
** 0 and NumBuckets-1. Offset is added to the parameter
451-
** before mapping it. Values which map to buckets outside
452-
** the range are truncated to fit within the range. Mapping
453-
** is done by truncating rather than rounding.
454-
** Return: Bucket number corresponding to Param + Offset.
455-
** Exceptions: none
456-
** History: Thu Feb 14 13:24:33 1991, DSJ, Created.
457-
*/
458-
return ClipToRange(static_cast<int>(MapParam(Param, Offset, NumBuckets)),
459-
0, NumBuckets - 1);
460-
} /* BucketFor */
461-
442+
// Returns a quantized bucket for the given param shifted by offset,
443+
// notionally (param + offset) * num_buckets, but clipped and casted to the
444+
// appropriate type.
445+
uinT8 Bucket8For(FLOAT32 param, FLOAT32 offset, int num_buckets) {
446+
int bucket = IntCastRounded(MapParam(param, offset, num_buckets));
447+
return static_cast<uinT8>(ClipToRange(bucket, 0, num_buckets - 1));
448+
}
449+
uinT16 Bucket16For(FLOAT32 param, FLOAT32 offset, int num_buckets) {
450+
int bucket = IntCastRounded(MapParam(param, offset, num_buckets));
451+
return static_cast<uinT16>(ClipToRange(bucket, 0, num_buckets - 1));
452+
}
462453

463454
/*---------------------------------------------------------------------------*/
464-
int CircBucketFor(FLOAT32 Param, FLOAT32 Offset, int NumBuckets) {
465-
/*
466-
** Parameters:
467-
** Param parameter value to map into a circular bucket
468-
** Offset amount to shift param before mapping it
469-
** NumBuckets number of buckets to map param into
470-
** Globals: none
471-
** Operation: This routine maps a parameter value into a bucket between
472-
** 0 and NumBuckets-1. Offset is added to the parameter
473-
** before mapping it. Values which map to buckets outside
474-
** the range are wrapped to a new value in a circular fashion.
475-
** Mapping is done by truncating rather than rounding.
476-
** Return: Bucket number corresponding to Param + Offset.
477-
** Exceptions: none
478-
** History: Thu Feb 14 13:24:33 1991, DSJ, Created.
479-
*/
480-
int Bucket;
481-
482-
Bucket = static_cast<int>(MapParam(Param, Offset, NumBuckets));
483-
if (Bucket < 0)
484-
Bucket += NumBuckets;
485-
else if (Bucket >= NumBuckets)
486-
Bucket -= NumBuckets;
487-
return Bucket;
455+
// Returns a quantized bucket for the given circular param shifted by offset,
456+
// notionally (param + offset) * num_buckets, but modded and casted to the
457+
// appropriate type.
458+
uinT8 CircBucketFor(FLOAT32 param, FLOAT32 offset, int num_buckets) {
459+
int bucket = IntCastRounded(MapParam(param, offset, num_buckets));
460+
return static_cast<uinT8>(Modulo(bucket, num_buckets));
488461
} /* CircBucketFor */
489462

490463

@@ -1694,23 +1667,23 @@ void InitTableFiller (FLOAT32 EndPad, FLOAT32 SidePad,
16941667

16951668
if (fabs (Angle - 0.0) < HV_TOLERANCE || fabs (Angle - 0.5) < HV_TOLERANCE) {
16961669
/* horizontal proto - handle as special case */
1697-
Filler->X = BucketFor(X - HalfLength - EndPad, XS, NB);
1698-
Filler->YStart = BucketFor(Y - SidePad, YS, NB * 256);
1699-
Filler->YEnd = BucketFor(Y + SidePad, YS, NB * 256);
1670+
Filler->X = Bucket8For(X - HalfLength - EndPad, XS, NB);
1671+
Filler->YStart = Bucket16For(Y - SidePad, YS, NB * 256);
1672+
Filler->YEnd = Bucket16For(Y + SidePad, YS, NB * 256);
17001673
Filler->StartDelta = 0;
17011674
Filler->EndDelta = 0;
17021675
Filler->Switch[0].Type = LastSwitch;
1703-
Filler->Switch[0].X = BucketFor(X + HalfLength + EndPad, XS, NB);
1676+
Filler->Switch[0].X = Bucket8For(X + HalfLength + EndPad, XS, NB);
17041677
} else if (fabs(Angle - 0.25) < HV_TOLERANCE ||
17051678
fabs(Angle - 0.75) < HV_TOLERANCE) {
17061679
/* vertical proto - handle as special case */
1707-
Filler->X = BucketFor(X - SidePad, XS, NB);
1708-
Filler->YStart = BucketFor(Y - HalfLength - EndPad, YS, NB * 256);
1709-
Filler->YEnd = BucketFor(Y + HalfLength + EndPad, YS, NB * 256);
1680+
Filler->X = Bucket8For(X - SidePad, XS, NB);
1681+
Filler->YStart = Bucket16For(Y - HalfLength - EndPad, YS, NB * 256);
1682+
Filler->YEnd = Bucket16For(Y + HalfLength + EndPad, YS, NB * 256);
17101683
Filler->StartDelta = 0;
17111684
Filler->EndDelta = 0;
17121685
Filler->Switch[0].Type = LastSwitch;
1713-
Filler->Switch[0].X = BucketFor(X + SidePad, XS, NB);
1686+
Filler->Switch[0].X = Bucket8For(X + SidePad, XS, NB);
17141687
} else {
17151688
/* diagonal proto */
17161689

@@ -1736,36 +1709,34 @@ void InitTableFiller (FLOAT32 EndPad, FLOAT32 SidePad,
17361709
}
17371710

17381711
/* translate into bucket positions and deltas */
1739-
Filler->X = (inT8) MapParam(Start.x, XS, NB);
1712+
Filler->X = Bucket8For(Start.x, XS, NB);
17401713
Filler->StartDelta = -(inT16) ((Cos / Sin) * 256);
17411714
Filler->EndDelta = (inT16) ((Sin / Cos) * 256);
17421715

17431716
XAdjust = BucketEnd(Filler->X, XS, NB) - Start.x;
17441717
YAdjust = XAdjust * Cos / Sin;
1745-
Filler->YStart = (inT16) MapParam(Start.y - YAdjust, YS, NB * 256);
1718+
Filler->YStart = Bucket16For(Start.y - YAdjust, YS, NB * 256);
17461719
YAdjust = XAdjust * Sin / Cos;
1747-
Filler->YEnd = (inT16) MapParam(Start.y + YAdjust, YS, NB * 256);
1720+
Filler->YEnd = Bucket16For(Start.y + YAdjust, YS, NB * 256);
17481721

17491722
Filler->Switch[S1].Type = StartSwitch;
1750-
Filler->Switch[S1].X = (inT8) MapParam(Switch1.x, XS, NB);
1751-
Filler->Switch[S1].Y = (inT8) MapParam(Switch1.y, YS, NB);
1723+
Filler->Switch[S1].X = Bucket8For(Switch1.x, XS, NB);
1724+
Filler->Switch[S1].Y = Bucket8For(Switch1.y, YS, NB);
17521725
XAdjust = Switch1.x - BucketStart(Filler->Switch[S1].X, XS, NB);
17531726
YAdjust = XAdjust * Sin / Cos;
1754-
Filler->Switch[S1].YInit =
1755-
(inT16) MapParam(Switch1.y - YAdjust, YS, NB * 256);
1727+
Filler->Switch[S1].YInit = Bucket16For(Switch1.y - YAdjust, YS, NB * 256);
17561728
Filler->Switch[S1].Delta = Filler->EndDelta;
17571729

17581730
Filler->Switch[S2].Type = EndSwitch;
1759-
Filler->Switch[S2].X = (inT8) MapParam(Switch2.x, XS, NB);
1760-
Filler->Switch[S2].Y = (inT8) MapParam(Switch2.y, YS, NB);
1731+
Filler->Switch[S2].X = Bucket8For(Switch2.x, XS, NB);
1732+
Filler->Switch[S2].Y = Bucket8For(Switch2.y, YS, NB);
17611733
XAdjust = Switch2.x - BucketStart(Filler->Switch[S2].X, XS, NB);
17621734
YAdjust = XAdjust * Cos / Sin;
1763-
Filler->Switch[S2].YInit =
1764-
(inT16) MapParam(Switch2.y + YAdjust, YS, NB * 256);
1735+
Filler->Switch[S2].YInit = Bucket16For(Switch2.y + YAdjust, YS, NB * 256);
17651736
Filler->Switch[S2].Delta = Filler->StartDelta;
17661737

17671738
Filler->Switch[2].Type = LastSwitch;
1768-
Filler->Switch[2].X = (inT8)MapParam(End.x, XS, NB);
1739+
Filler->Switch[2].X = Bucket8For(End.x, XS, NB);
17691740
} else {
17701741
/* falling diagonal proto */
17711742
Angle *= 2.0 * PI;
@@ -1788,36 +1759,34 @@ void InitTableFiller (FLOAT32 EndPad, FLOAT32 SidePad,
17881759
}
17891760

17901761
/* translate into bucket positions and deltas */
1791-
Filler->X = (inT8) MapParam(Start.x, XS, NB);
1762+
Filler->X = Bucket8For(Start.x, XS, NB);
17921763
Filler->StartDelta = -(inT16) ((Sin / Cos) * 256);
17931764
Filler->EndDelta = (inT16) ((Cos / Sin) * 256);
17941765

17951766
XAdjust = BucketEnd(Filler->X, XS, NB) - Start.x;
17961767
YAdjust = XAdjust * Sin / Cos;
1797-
Filler->YStart = (inT16) MapParam(Start.y - YAdjust, YS, NB * 256);
1768+
Filler->YStart = Bucket16For(Start.y - YAdjust, YS, NB * 256);
17981769
YAdjust = XAdjust * Cos / Sin;
1799-
Filler->YEnd = (inT16) MapParam(Start.y + YAdjust, YS, NB * 256);
1770+
Filler->YEnd = Bucket16For(Start.y + YAdjust, YS, NB * 256);
18001771

18011772
Filler->Switch[S1].Type = EndSwitch;
1802-
Filler->Switch[S1].X = (inT8) MapParam(Switch1.x, XS, NB);
1803-
Filler->Switch[S1].Y = (inT8) MapParam(Switch1.y, YS, NB);
1773+
Filler->Switch[S1].X = Bucket8For(Switch1.x, XS, NB);
1774+
Filler->Switch[S1].Y = Bucket8For(Switch1.y, YS, NB);
18041775
XAdjust = Switch1.x - BucketStart(Filler->Switch[S1].X, XS, NB);
18051776
YAdjust = XAdjust * Sin / Cos;
1806-
Filler->Switch[S1].YInit =
1807-
(inT16) MapParam(Switch1.y + YAdjust, YS, NB * 256);
1777+
Filler->Switch[S1].YInit = Bucket16For(Switch1.y + YAdjust, YS, NB * 256);
18081778
Filler->Switch[S1].Delta = Filler->StartDelta;
18091779

18101780
Filler->Switch[S2].Type = StartSwitch;
1811-
Filler->Switch[S2].X = (inT8) MapParam(Switch2.x, XS, NB);
1812-
Filler->Switch[S2].Y = (inT8) MapParam(Switch2.y, YS, NB);
1781+
Filler->Switch[S2].X = Bucket8For(Switch2.x, XS, NB);
1782+
Filler->Switch[S2].Y = Bucket8For(Switch2.y, YS, NB);
18131783
XAdjust = Switch2.x - BucketStart(Filler->Switch[S2].X, XS, NB);
18141784
YAdjust = XAdjust * Cos / Sin;
1815-
Filler->Switch[S2].YInit =
1816-
(inT16) MapParam(Switch2.y - YAdjust, YS, NB * 256);
1785+
Filler->Switch[S2].YInit = Bucket16For(Switch2.y - YAdjust, YS, NB * 256);
18171786
Filler->Switch[S2].Delta = Filler->EndDelta;
18181787

18191788
Filler->Switch[2].Type = LastSwitch;
1820-
Filler->Switch[2].X = (inT8) MapParam(End.x, XS, NB);
1789+
Filler->Switch[2].X = Bucket8For(End.x, XS, NB);
18211790
}
18221791
}
18231792
} /* InitTableFiller */

classify/intproto.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -218,9 +218,10 @@ void AddProtoToClassPruner(PROTO Proto,
218218
void AddProtoToProtoPruner(PROTO Proto, int ProtoId,
219219
INT_CLASS Class, bool debug);
220220

221-
int BucketFor(FLOAT32 Param, FLOAT32 Offset, int NumBuckets);
221+
uinT8 Bucket8For(FLOAT32 param, FLOAT32 offset, int num_buckets);
222+
uinT16 Bucket16For(FLOAT32 param, FLOAT32 offset, int num_buckets);
222223

223-
int CircBucketFor(FLOAT32 Param, FLOAT32 Offset, int NumBuckets);
224+
uinT8 CircBucketFor(FLOAT32 param, FLOAT32 offset, int num_buckets);
224225

225226
void UpdateMatchDisplay();
226227

0 commit comments

Comments
 (0)