Commit 1abcfbdc5fae0621a3373bc589a7aac339ce6426

Authored by Charles Otto
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.
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());