Commit 1abcfbdc5fae0621a3373bc589a7aac339ce6426
1 parent
5bab078d
Make project on timeVaryingTransforms safer
Add a TimeInvariantWrapperTransform member of TimeVaryingTransform, and use that in TimeVaryingTransform::project for thread safety. This is the strategy previously used in Distribute, but putting the alias on TimeVaryingTransform gives us more safety if Distribute is not in fact the top level transform. Note: copies are only made off of calls to project, so having the alias on every TimeVaryingTransform is not too wasteful.
Showing
3 changed files
with
91 additions
and
68 deletions
openbr/plugins/meta.cpp
| @@ -264,7 +264,6 @@ class ContractTransform : public UntrainableMetaTransform | @@ -264,7 +264,6 @@ class ContractTransform : public UntrainableMetaTransform | ||
| 264 | 264 | ||
| 265 | virtual void project(const TemplateList &src, TemplateList &dst) const | 265 | virtual void project(const TemplateList &src, TemplateList &dst) const |
| 266 | { | 266 | { |
| 267 | - //dst = Expanded(src); | ||
| 268 | if (src.empty()) return; | 267 | if (src.empty()) return; |
| 269 | Template out; | 268 | Template out; |
| 270 | 269 | ||
| @@ -682,8 +681,10 @@ public: | @@ -682,8 +681,10 @@ public: | ||
| 682 | 681 | ||
| 683 | void init() | 682 | void init() |
| 684 | { | 683 | { |
| 685 | - if (transform && transform->timeVarying()) | ||
| 686 | - transform = new br::TimeInvariantWrapperTransform(transform); | 684 | + if (!transform) |
| 685 | + return; | ||
| 686 | + | ||
| 687 | + trainable = transform->trainable; | ||
| 687 | } | 688 | } |
| 688 | 689 | ||
| 689 | }; | 690 | }; |
openbr/plugins/openbr_internal.h
| @@ -24,81 +24,27 @@ private: | @@ -24,81 +24,27 @@ private: | ||
| 24 | }; | 24 | }; |
| 25 | 25 | ||
| 26 | /*! | 26 | /*! |
| 27 | - * \brief A br::MetaTransform that does not require training data. | 27 | + * \brief A br::Transform expecting multiple matrices per template. |
| 28 | */ | 28 | */ |
| 29 | -class BR_EXPORT UntrainableMetaTransform : public UntrainableTransform | 29 | +class BR_EXPORT MetaTransform : public Transform |
| 30 | { | 30 | { |
| 31 | Q_OBJECT | 31 | Q_OBJECT |
| 32 | 32 | ||
| 33 | protected: | 33 | protected: |
| 34 | - UntrainableMetaTransform() : UntrainableTransform(false) {} | ||
| 35 | -}; | ||
| 36 | - | ||
| 37 | -/*! | ||
| 38 | - * \brief A br::Transform for which the results of project may change due to prior calls to project | ||
| 39 | - */ | ||
| 40 | -class BR_EXPORT TimeVaryingTransform : public Transform | ||
| 41 | -{ | ||
| 42 | - Q_OBJECT | ||
| 43 | - | ||
| 44 | -public: | ||
| 45 | - virtual bool timeVarying() const { return true; } | ||
| 46 | - | ||
| 47 | - virtual void project(const Template &src, Template &dst) const | ||
| 48 | - { | ||
| 49 | - qFatal("No const project defined for time-varying transform"); | ||
| 50 | - (void) dst; (void) src; | ||
| 51 | - } | ||
| 52 | - | ||
| 53 | - virtual void project(const TemplateList &src, TemplateList &dst) const | ||
| 54 | - { | ||
| 55 | - qFatal("No const project defined for time-varying transform"); | ||
| 56 | - (void) dst; (void) src; | ||
| 57 | - } | ||
| 58 | - | ||
| 59 | - // Get a compile failure if this isn't here to go along with the other | ||
| 60 | - // projectUpdate, no idea why | ||
| 61 | - virtual void projectUpdate(const Template & src, Template & dst) | ||
| 62 | - { | ||
| 63 | - (void) src; (void) dst; | ||
| 64 | - qFatal("do something useful"); | ||
| 65 | - } | ||
| 66 | - | ||
| 67 | - virtual void projectUpdate(const TemplateList &src, TemplateList &dst) | ||
| 68 | - { | ||
| 69 | - foreach (const Template & src_part, src) { | ||
| 70 | - Template out; | ||
| 71 | - projectUpdate(src_part, out); | ||
| 72 | - dst.append(out); | ||
| 73 | - } | ||
| 74 | - } | ||
| 75 | - | ||
| 76 | - /*! | ||
| 77 | - *\brief For transforms that don't do any training, this default implementation | ||
| 78 | - * which creates a new copy of the Transform from its description string is sufficient. | ||
| 79 | - */ | ||
| 80 | - virtual Transform * smartCopy() | ||
| 81 | - { | ||
| 82 | - return this->clone(); | ||
| 83 | - } | ||
| 84 | - | ||
| 85 | - | ||
| 86 | -protected: | ||
| 87 | - TimeVaryingTransform(bool independent = true, bool trainable = true) : Transform(independent, trainable) {} | 34 | + MetaTransform() : Transform(false) {} |
| 88 | }; | 35 | }; |
| 89 | 36 | ||
| 90 | /*! | 37 | /*! |
| 91 | - * \brief A br::Transform expecting multiple matrices per template. | 38 | + * \brief A br::MetaTransform that does not require training data. |
| 92 | */ | 39 | */ |
| 93 | -class BR_EXPORT MetaTransform : public Transform | 40 | +class BR_EXPORT UntrainableMetaTransform : public UntrainableTransform |
| 94 | { | 41 | { |
| 95 | Q_OBJECT | 42 | Q_OBJECT |
| 96 | 43 | ||
| 97 | protected: | 44 | protected: |
| 98 | - MetaTransform() : Transform(false) {} | 45 | + UntrainableMetaTransform() : UntrainableTransform(false) {} |
| 99 | }; | 46 | }; |
| 100 | 47 | ||
| 101 | - | ||
| 102 | class TransformCopier : public ResourceMaker<Transform> | 48 | class TransformCopier : public ResourceMaker<Transform> |
| 103 | { | 49 | { |
| 104 | public: | 50 | public: |
| @@ -151,6 +97,71 @@ private: | @@ -151,6 +97,71 @@ private: | ||
| 151 | Transform * baseTransform; | 97 | Transform * baseTransform; |
| 152 | }; | 98 | }; |
| 153 | 99 | ||
| 100 | +/*! | ||
| 101 | + * \brief A br::Transform for which the results of project may change due to prior calls to project | ||
| 102 | + */ | ||
| 103 | +class BR_EXPORT TimeVaryingTransform : public Transform | ||
| 104 | +{ | ||
| 105 | + Q_OBJECT | ||
| 106 | + | ||
| 107 | +public: | ||
| 108 | + | ||
| 109 | + virtual bool timeVarying() const { return true; } | ||
| 110 | + | ||
| 111 | + virtual void project(const Template &src, Template &dst) const | ||
| 112 | + { | ||
| 113 | + timeInvariantAlias->project(src,dst); | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + virtual void project(const TemplateList &src, TemplateList &dst) const | ||
| 117 | + { | ||
| 118 | + timeInvariantAlias->project(src,dst); | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + // Get a compile failure if this isn't here to go along with the other | ||
| 122 | + // projectUpdate, no idea why | ||
| 123 | + virtual void projectUpdate(const Template & src, Template & dst) | ||
| 124 | + { | ||
| 125 | + (void) src; (void) dst; | ||
| 126 | + qFatal("do something useful"); | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + virtual void projectUpdate(const TemplateList &src, TemplateList &dst) | ||
| 130 | + { | ||
| 131 | + foreach (const Template & src_part, src) { | ||
| 132 | + Template out; | ||
| 133 | + projectUpdate(src_part, out); | ||
| 134 | + dst.append(out); | ||
| 135 | + } | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + /*! | ||
| 139 | + *\brief For transforms that don't do any training, this default implementation | ||
| 140 | + * which creates a new copy of the Transform from its description string is sufficient. | ||
| 141 | + */ | ||
| 142 | + virtual Transform * smartCopy() | ||
| 143 | + { | ||
| 144 | + return this->clone(); | ||
| 145 | + } | ||
| 146 | + | ||
| 147 | + void init() | ||
| 148 | + { | ||
| 149 | + delete timeInvariantAlias; | ||
| 150 | + timeInvariantAlias = new TimeInvariantWrapperTransform(this); | ||
| 151 | + } | ||
| 152 | + | ||
| 153 | +protected: | ||
| 154 | + Transform * timeInvariantAlias; | ||
| 155 | + TimeVaryingTransform(bool independent = true, bool trainable = true) : Transform(independent, trainable) | ||
| 156 | + { | ||
| 157 | + timeInvariantAlias = NULL; | ||
| 158 | + } | ||
| 159 | + ~TimeVaryingTransform() | ||
| 160 | + { | ||
| 161 | + delete timeInvariantAlias; | ||
| 162 | + } | ||
| 163 | +}; | ||
| 164 | + | ||
| 154 | 165 | ||
| 155 | /*! | 166 | /*! |
| 156 | * \brief A MetaTransform that aggregates some sub-transforms | 167 | * \brief A MetaTransform that aggregates some sub-transforms |
| @@ -165,15 +176,17 @@ public: | @@ -165,15 +176,17 @@ public: | ||
| 165 | 176 | ||
| 166 | virtual void project(const Template &src, Template &dst) const | 177 | virtual void project(const Template &src, Template &dst) const |
| 167 | { | 178 | { |
| 168 | - if (timeVarying()) qFatal("No const project defined for time-varying transform"); | 179 | + if (timeVarying()) { |
| 180 | + timeInvariantAlias->project(src,dst); | ||
| 181 | + return; | ||
| 182 | + } | ||
| 169 | _project(src, dst); | 183 | _project(src, dst); |
| 170 | } | 184 | } |
| 171 | 185 | ||
| 172 | virtual void project(const TemplateList &src, TemplateList &dst) const | 186 | virtual void project(const TemplateList &src, TemplateList &dst) const |
| 173 | { | 187 | { |
| 174 | if (timeVarying()) { | 188 | if (timeVarying()) { |
| 175 | - CompositeTransform * non_const = const_cast<CompositeTransform *>(this); | ||
| 176 | - non_const->projectUpdate(src,dst); | 189 | + timeInvariantAlias->project(src,dst); |
| 177 | return; | 190 | return; |
| 178 | } | 191 | } |
| 179 | _project(src, dst); | 192 | _project(src, dst); |
| @@ -190,6 +203,10 @@ public: | @@ -190,6 +203,10 @@ public: | ||
| 190 | isTimeVarying = isTimeVarying || transform->timeVarying(); | 203 | isTimeVarying = isTimeVarying || transform->timeVarying(); |
| 191 | trainable = trainable || transform->trainable; | 204 | trainable = trainable || transform->trainable; |
| 192 | } | 205 | } |
| 206 | + | ||
| 207 | + // If we are time varying, set up timeInvariantAlias | ||
| 208 | + if (this->timeVarying()) | ||
| 209 | + TimeVaryingTransform::init(); | ||
| 193 | } | 210 | } |
| 194 | 211 | ||
| 195 | /*! | 212 | /*! |
openbr/plugins/stream.cpp
| @@ -707,8 +707,7 @@ public: | @@ -707,8 +707,7 @@ public: | ||
| 707 | if (input == NULL) { | 707 | if (input == NULL) { |
| 708 | qFatal("null input to multi-thread stage"); | 708 | qFatal("null input to multi-thread stage"); |
| 709 | } | 709 | } |
| 710 | - // Project the input we got | ||
| 711 | - transform->projectUpdate(input->data); | 710 | + input->data >> *transform; |
| 712 | 711 | ||
| 713 | should_continue = nextStage->tryAcquireNextStage(input); | 712 | should_continue = nextStage->tryAcquireNextStage(input); |
| 714 | 713 | ||
| @@ -1300,6 +1299,12 @@ public: | @@ -1300,6 +1299,12 @@ public: | ||
| 1300 | { | 1299 | { |
| 1301 | if (!transform) | 1300 | if (!transform) |
| 1302 | return; | 1301 | return; |
| 1302 | + | ||
| 1303 | + // Set up timeInvariantAlias | ||
| 1304 | + // this is only safe because copies are actually made in project | ||
| 1305 | + // calls, not during init. | ||
| 1306 | + TimeVaryingTransform::init(); | ||
| 1307 | + | ||
| 1303 | trainable = transform->trainable; | 1308 | trainable = transform->trainable; |
| 1304 | 1309 | ||
| 1305 | basis.setParent(this->parent()); | 1310 | basis.setParent(this->parent()); |