bounding_layer.cpp
1// OpenNN: Open Neural Networks Library
2// www.opennn.net
3//
4// B O U N D I N G L A Y E R C L A S S
5//
6// Artificial Intelligence Techniques SL
7// artelnics@artelnics.com
8
9#include "bounding_layer.h"
10
11namespace OpenNN
12{
13
16
18{
19 set();
20
22}
23
24
28
29BoundingLayer::BoundingLayer(const Index& neurons_number) : Layer()
30{
31 set(neurons_number);
32
34}
35
36
39
41{
42}
43
44
46
48{
49 if(get_neurons_number() == 0)
50 {
51 return true;
52 }
53 else
54 {
55 return false;
56 }
57}
58
59
61
63{
64 return bounding_method;
65}
66
68
70{
71 if(bounding_method == BoundingMethod::Bounding)
72 {
73 return "Bounding";
74 }
75 else if(bounding_method == BoundingMethod::NoBounding)
76 {
77 return "NoBounding";
78 }
79 else
80 {
81 ostringstream buffer;
82
83 buffer << "OpenNN Exception: BoundingLayer class.\n"
84 << "string write_bounding_method() const method.\n"
85 << "Unknown bounding method.\n";
86
87 throw logic_error(buffer.str());
88 }
89}
90
91
93
95{
96 return lower_bounds.dimension(0);
97}
98
99
101
103{
104 return lower_bounds.dimension(0);
105}
106
107
109
110const Tensor<type, 1>& BoundingLayer::get_lower_bounds() const
111{
112 return lower_bounds;
113}
114
115
118
119type BoundingLayer::get_lower_bound(const Index& i) const
120{
121#ifdef OPENNN_DEBUG
122
123 const Index neurons_number = get_neurons_number();
124
125 if(i >= neurons_number)
126 {
127 ostringstream buffer;
128
129 buffer << "OpenNN Exception: BoundingLayer class.\n"
130 << "type get_lower_bound(const Index&) const method.\n"
131 << "Index must be less than number of bounding neurons.\n";
132
133 throw logic_error(buffer.str());
134 }
135
136#endif
137
138 return lower_bounds[i];
139}
140
141
143
144const Tensor<type, 1>& BoundingLayer::get_upper_bounds() const
145{
146 return upper_bounds;
147}
148
149
152
153type BoundingLayer::get_upper_bound(const Index& i) const
154{
155#ifdef OPENNN_DEBUG
156
157 const Index neurons_number = get_neurons_number();
158
159 if(neurons_number == 0)
160 {
161 ostringstream buffer;
162
163 buffer << "OpenNN Exception: BoundingLayer class.\n"
164 << "type get_upper_bound(const Index&) const method.\n"
165 << "Number of bounding neurons is zero.\n";
166
167 throw logic_error(buffer.str());
168 }
169 else if(i >= neurons_number)
170 {
171 ostringstream buffer;
172
173 buffer << "OpenNN Exception: BoundingLayer class.\n"
174 << "type get_upper_bound(const Index&) const method.\n"
175 << "Index must be less than number of bounding neurons.\n";
176
177 throw logic_error(buffer.str());
178 }
179
180#endif
181
182 return upper_bounds(i);
183}
184
185
188
190{
191 bounding_method = BoundingMethod::Bounding;
192
193 lower_bounds.resize(0);
194 upper_bounds.resize(0);
195
196 set_default();
197}
198
199
203
204void BoundingLayer::set(const Index& new_neurons_number)
205{
206 set_neurons_number(new_neurons_number);
207
208 set_default();
209}
210
211
214
215void BoundingLayer::set_inputs_number(const Index& new_inputs_number)
216{
217 lower_bounds.resize(new_inputs_number);
218 upper_bounds.resize(new_inputs_number);
219}
220
221
224
225void BoundingLayer::set_neurons_number(const Index& new_neurons_number)
226{
227 lower_bounds.resize(new_neurons_number);
228 upper_bounds.resize(new_neurons_number);
229
230 lower_bounds.setConstant(-numeric_limits<type>::max());
231 upper_bounds.setConstant(numeric_limits<type>::max());
232}
233
234
237
238void BoundingLayer::set(const tinyxml2::XMLDocument& bounding_layer_document)
239{
240 set_default();
241
242 from_XML(bounding_layer_document);
243}
244
245
248
249void BoundingLayer::set(const BoundingLayer& other_bounding_layer)
250{
251 lower_bounds = other_bounding_layer.lower_bounds;
252
253 upper_bounds = other_bounding_layer.upper_bounds;
254
255 display = other_bounding_layer.display;
256}
257
258
261
263{
264 bounding_method = new_method;
265}
266
267
270
271void BoundingLayer::set_bounding_method(const string& new_method_string)
272{
273 if(new_method_string == "NoBounding")
274 {
275 bounding_method = BoundingMethod::NoBounding;
276 }
277 else if(new_method_string == "Bounding")
278 {
279 bounding_method = BoundingMethod::Bounding;
280 }
281 else
282 {
283 ostringstream buffer;
284
285 buffer << "OpenNN Exception: BoundingLayer class.\n"
286 << "void set_bounding_method(const string&) method.\n"
287 << "Unknown bounding method: " << new_method_string << ".\n";
288
289 throw logic_error(buffer.str());
290 }
291}
292
293
296
297void BoundingLayer::set_lower_bounds(const Tensor<type, 1>& new_lower_bounds)
298{
299#ifdef OPENNN_DEBUG
300
301 const Index neurons_number = get_neurons_number();
302
303 if(new_lower_bounds.size() != neurons_number)
304 {
305 ostringstream buffer;
306
307 buffer << "OpenNN Exception: BoundingLayer class.\n"
308 << "void set_lower_bounds(const Tensor<type, 1>&) method.\n"
309 << "Size must be equal to number of bounding neurons number.\n";
310
311 throw logic_error(buffer.str());
312 }
313
314#endif
315
316 // Set lower bound of bounding neurons
317
318 lower_bounds = new_lower_bounds;
319}
320
321
326
327void BoundingLayer::set_lower_bound(const Index& index, const type& new_lower_bound)
328{
329 const Index neurons_number = get_neurons_number();
330
331#ifdef OPENNN_DEBUG
332
333 if(index >= neurons_number)
334 {
335 ostringstream buffer;
336
337 buffer << "OpenNN Exception: BoundingLayer class.\n"
338 << "void set_lower_bound(const Index&, const type&) method.\n"
339 << "Index of bounding neurons must be less than number of bounding neurons.\n";
340
341 throw logic_error(buffer.str());
342 }
343
344#endif
345
346 if(lower_bounds.size() != neurons_number)
347 {
348 lower_bounds.resize(neurons_number);
349 lower_bounds.setConstant(-numeric_limits<type>::max());
350 }
351
352 // Set lower bound of single neuron
353
354 lower_bounds[index] = new_lower_bound;
355}
356
357
361
362void BoundingLayer::set_upper_bounds(const Tensor<type, 1>& new_upper_bounds)
363{
364#ifdef OPENNN_DEBUG
365check_size(new_upper_bounds, get_neurons_number(), LOG);
366#endif
367
368 // Set upper bound of neurons
369
370 upper_bounds = new_upper_bounds;
371}
372
373
378
379void BoundingLayer::set_upper_bound(const Index& index, const type& new_upper_bound)
380{
381 const Index neurons_number = get_neurons_number();
382
383#ifdef OPENNN_DEBUG
384
385 if(index >= neurons_number)
386 {
387 ostringstream buffer;
388
389 buffer << "OpenNN Exception: BoundingLayer class.\n"
390 << "void set_upper_bound(const Index&, const type&) method.\n"
391 << "Index of bounding neuron must be less than number of bounding neurons.\n";
392
393 throw logic_error(buffer.str());
394 }
395
396#endif
397
398 if(upper_bounds.size() != neurons_number)
399 {
400 upper_bounds.resize(neurons_number);
401 upper_bounds.setConstant(numeric_limits<type>::max());
402 }
403
404 upper_bounds[index] = new_upper_bound;
405
406}
407
408
413
414void BoundingLayer::set_display(const bool& new_display)
415{
416 display = new_display;
417}
418
419
424
426{
427 layer_name = "bounding_layer";
428
429 bounding_method = BoundingMethod::Bounding;
430
431 layer_type = Layer::Type::Bounding;
432}
433
434
437
438Tensor<type, 2> BoundingLayer::calculate_outputs(const Tensor<type, 2>& inputs)
439{
440#ifdef OPENNN_DEBUG
441check_columns_number(inputs, get_inputs_number(), LOG);
442#endif
443
444 switch(bounding_method)
445 {
446 case BoundingMethod::NoBounding: return inputs;
447
448 case BoundingMethod::Bounding:
449 {
450 const Index rows_number = inputs.dimension(0);
451 const Index columns_number = inputs.dimension(1);
452
453 Tensor<type, 2> outputs(rows_number, columns_number);
454
455 for(Index i = 0; i < rows_number; i++)
456 {
457 for(Index j = 0; j < columns_number; j++)
458 {
459 if(inputs(i,j) < lower_bounds(j)) outputs(i,j) = lower_bounds(j);
460 else if(inputs(i,j) > upper_bounds(j)) outputs(i,j) = upper_bounds(j);
461 else outputs(i,j) = inputs(i,j);
462 }
463 }
464
465 return outputs;
466 }
467 }
468
469 return Tensor<type, 2>();
470}
471
472
474
475string BoundingLayer::write_expression(const Tensor<string, 1>& inputs_names, const Tensor<string, 1>& outputs_names) const
476{
477 ostringstream buffer;
478
479 buffer.precision(10);
480
481 if(bounding_method == BoundingMethod::Bounding)
482 {
483 const Index neurons_number = get_neurons_number();
484
485 for(Index i = 0; i < neurons_number; i++)
486 {
487 buffer << outputs_names[i] << " = max(" << lower_bounds[i] << ", " << inputs_names[i] << ")\n";
488 buffer << outputs_names[i] << " = min(" << upper_bounds[i] << ", " << inputs_names[i] << ")\n";
489 }
490 }
491 else
492 {
493 buffer << "";
494 }
495
496 return buffer.str();
497}
498
499
503
505{
506 const Index neurons_number = get_neurons_number();
507
508 ostringstream buffer;
509
510 buffer << "vector<float> " << layer_name << "(const vector<float>& inputs)\n{" << endl;
511
512 buffer << "\tvector<float> outputs(" << neurons_number << ");\n" << endl;
513
514
515 if(bounding_method == BoundingMethod::Bounding)
516 {
517 for(Index i = 0; i < neurons_number; i++)
518 {
519 buffer << "\tif(inputs[" << i << "] < " << lower_bounds[i] << ")" << endl;
520 buffer << "\t{" << endl;
521 buffer << "\t outputs[" << i << "] = " << lower_bounds[i] << endl;
522 buffer << "\t}" << endl;
523 buffer << "\telse if(inputs[" << i << "] > " << upper_bounds[i] << ")" << endl;
524 buffer << "\t{" << endl;
525 buffer << "\t outputs[" << i << "] = " << upper_bounds[i] << endl;
526 buffer << "\t}" << endl;
527 buffer << "\telse" << endl;
528 buffer << "\t{" << endl;
529 buffer << "\t outputs[" << i << "] = inputs[" << i << "];" << endl;
530 buffer << "\t}" << endl;
531 }
532 }
533 else
534 {
535 for(Index i = 0; i < neurons_number; i++)
536 {
537 buffer << "\toutputs[" << i << "] = inputs[" << i << "];" << endl;
538 }
539 }
540
541 buffer << "\n\treturn outputs;\n}" << endl;
542
543 return buffer.str();
544}
545
546
550
552{
553 const Index neurons_number = get_neurons_number();
554
555 ostringstream buffer;
556
557 buffer << "\tdef " << layer_name << "(self,inputs):\n" << endl;
558
559 buffer << "\t\toutputs = [None] * "<<neurons_number<<"\n" << endl;
560
561 if(bounding_method == BoundingMethod::Bounding)
562 {
563 for(Index i = 0; i < neurons_number; i++)
564 {
565 buffer << "\t\tif inputs[" << i << "] < " << lower_bounds[i] << ":\n" << endl;
566 buffer << "\t\t\toutputs[" << i << "] = " << lower_bounds[i] << "\n" << endl;
567 buffer << "\t\telif inputs[" << i << "] >" << upper_bounds[i] << ":\n" << endl;
568 buffer << "\t\t\toutputs[" << i << "] = " << upper_bounds[i] << "\n" << endl;
569 buffer << "\t\telse:\n" << endl;
570 buffer << "\t\t\toutputs[" << i << "] = inputs[" << i << "]\n"<< endl;
571 }
572 }
573 else
574 {
575 for(Index i = 0; i < neurons_number; i++)
576 {
577 buffer << "\t\toutputs[" << i << "] = inputs[" << i << "]" << endl;
578 }
579 }
580
581 buffer << "\n\t\treturn outputs\n" << endl;
582
583 return buffer.str();
584}
585
586
589
591{
592 ostringstream buffer;
593
594 file_stream.OpenElement("BoundingLayer");
595
596 // Bounding neurons number
597
598 file_stream.OpenElement("BoundingNeuronsNumber");
599
600 const Index neurons_number = get_neurons_number();
601
602 buffer.str("");
603 buffer << neurons_number;
604
605 file_stream.PushText(buffer.str().c_str());
606
607 file_stream.CloseElement();
608
609 for(Index i = 0; i < neurons_number; i++)
610 {
611 file_stream.OpenElement("Item");
612
613 file_stream.PushAttribute("Index", static_cast<unsigned>(i+1));
614
615 // Lower bound
616
617 file_stream.OpenElement("LowerBound");
618
619 buffer.str("");
620 buffer << lower_bounds[i];
621
622 file_stream.PushText(buffer.str().c_str());
623
624 file_stream.CloseElement();
625
626 // Upper bound
627
628 file_stream.OpenElement("UpperBound");
629
630 buffer.str("");
631 buffer << upper_bounds[i];
632
633 file_stream.PushText(buffer.str().c_str());
634
635 file_stream.CloseElement();
636
637
638 file_stream.CloseElement();
639 }
640
641 // Bounding method
642
643 file_stream.OpenElement("UseBoundingLayer");
644
645 if(bounding_method == BoundingMethod::Bounding)
646 {
647 buffer.str("");
648 buffer << 1;
649 }
650 else if(bounding_method == BoundingMethod::NoBounding)
651 {
652 buffer.str("");
653 buffer << 0;
654 }
655 else
656 {
657 file_stream.CloseElement();
658
659 buffer << "OpenNN Exception: BoundingLayer class.\n"
660 << "void write_XML(tinyxml2::XMLPrinter&) const method.\n"
661 << "Unknown bounding method type.\n";
662
663 throw logic_error(buffer.str());
664 }
665
666 file_stream.PushText(buffer.str().c_str());
667
668 file_stream.CloseElement();
669
670 // Display
671
672// {
673// file_stream.OpenElement("Display");
674
675// buffer.str("");
676// buffer << display;
677
678// file_stream.PushText(buffer.str().c_str());
679
680// file_stream.CloseElement();
681// }
682
683 file_stream.CloseElement();
684}
685
686
689
691{
692 ostringstream buffer;
693
694 const tinyxml2::XMLElement* bounding_layer_element = document.FirstChildElement("BoundingLayer");
695
696 if(!bounding_layer_element)
697 {
698 buffer << "OpenNN Exception: BoundingLayer class.\n"
699 << "void from_XML(const tinyxml2::XMLDocument&) method.\n"
700 << "BoundingLayer element is nullptr.\n";
701
702 throw logic_error(buffer.str());
703 }
704
705 // Bounding neurons number
706
707 const tinyxml2::XMLElement* neurons_number_element = bounding_layer_element->FirstChildElement("BoundingNeuronsNumber");
708
709 if(!neurons_number_element)
710 {
711 buffer << "OpenNN Exception: BoundingLayer class.\n"
712 << "void from_XML(const tinyxml2::XMLDocument&) method.\n"
713 << "BoundingNeuronsNumber element is nullptr.\n";
714
715 throw logic_error(buffer.str());
716 }
717
718 const Index neurons_number = static_cast<Index>(atoi(neurons_number_element->GetText()));
719
720 set(neurons_number);
721
722 unsigned index = 0; // Index does not work
723
724 if(neurons_number > 0)
725 {
726 const tinyxml2::XMLElement* start_element = neurons_number_element;
727
728 for(Index i = 0; i < lower_bounds.size(); i++)
729 {
730 const tinyxml2::XMLElement* item_element = start_element->NextSiblingElement("Item");
731 start_element = item_element;
732
733 if(!item_element)
734 {
735 buffer << "OpenNN Exception: BoundingLayer class.\n"
736 << "void from_XML(const tinyxml2::XMLElement*) method.\n"
737 << "Item " << i+1 << " is nullptr.\n";
738
739 throw logic_error(buffer.str());
740 }
741
742 item_element->QueryUnsignedAttribute("Index", &index);
743
744 if(index != i+1)
745 {
746 buffer << "OpenNN Exception: BoundingLayer class.\n"
747 << "void from_XML(const tinyxml2::XMLElement*) method.\n"
748 << "Index " << index << " is not correct.\n";
749
750 throw logic_error(buffer.str());
751 }
752
753 // Lower bound
754
755 const tinyxml2::XMLElement* lower_bound_element = item_element->FirstChildElement("LowerBound");
756
757 if(lower_bound_element)
758 {
759 if(lower_bound_element->GetText())
760 {
761 lower_bounds[index-1] = static_cast<type>(atof(lower_bound_element->GetText()));
762 }
763 }
764
765 // Upper bound
766
767 const tinyxml2::XMLElement* upper_bound_element = item_element->FirstChildElement("UpperBound");
768
769 if(upper_bound_element)
770 {
771 if(upper_bound_element->GetText())
772 {
773 upper_bounds[index-1] = static_cast<type>(atof(upper_bound_element->GetText()));
774 }
775 }
776 }
777 }
778
779 // Use bounding layer
780 {
781 const tinyxml2::XMLElement* use_bounding_layer_element = bounding_layer_element->FirstChildElement("UseBoundingLayer");
782
783 if(use_bounding_layer_element)
784 {
785 Index new_method = static_cast<Index>(atoi(use_bounding_layer_element->GetText()));
786
787 if(new_method == 1)
788 {
789 bounding_method = BoundingMethod::Bounding;
790 }
791 else if(new_method == 0)
792 {
793 bounding_method = BoundingMethod::NoBounding;
794 }
795 else
796 {
797 buffer << "OpenNN Exception: BoundingLayer class.\n"
798 << "void from_XML(const tinyxml2::XMLElement*) method.\n"
799 << "Unknown bounding method.\n";
800
801 throw logic_error(buffer.str());
802 }
803 }
804 }
805}
806
807}
808
809// OpenNN: Open Neural Networks Library.
810// Copyright(C) 2005-2021 Artificial Intelligence Techniques, SL.
811//
812// This library is free software; you can redistribute it and/or
813// modify it under the terms of the GNU Lesser General Public
814// License as published by the Free Software Foundation; either
815// version 2.1 of the License, or any later version.
816//
817// This library is distributed in the hope that it will be useful,
818// but WITHOUT ANY WARRANTY; without even the implied warranty of
819// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
820// Lesser General Public License for more details.
821
822// You should have received a copy of the GNU Lesser General Public
823// License along with this library; if not, write to the Free Software
824// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
This class represents a layer of bounding neurons.
void set_lower_bounds(const Tensor< type, 1 > &)
string write_expression_c() const
BoundingLayer::write_expression_c.
void set_upper_bound(const Index &, const type &)
type get_upper_bound(const Index &) const
void set_lower_bound(const Index &, const type &)
Index get_inputs_number() const
Get number of inputs.
string write_expression(const Tensor< string, 1 > &, const Tensor< string, 1 > &) const
Returns a string with the expression of the lower and upper bounds functions.
void from_XML(const tinyxml2::XMLDocument &)
string write_expression_python() const
BoundingLayer::write_expression_python.
bool display
Display messages to screen.
Tensor< type, 1 > lower_bounds
Lower bounds of output variables.
bool is_empty() const
Returns true if the size of the layer is zero, and false otherwise.
BoundingMethod
Enumeration of available methods for bounding the output variables.
const BoundingMethod & get_bounding_method() const
Returns the method used for bounding layer.
void set_inputs_number(const Index &)
Tensor< type, 2 > calculate_outputs(const Tensor< type, 2 > &)
Index get_neurons_number() const
Return the neurons number in the bounding layer.
void set_upper_bounds(const Tensor< type, 1 > &)
const Tensor< type, 1 > & get_upper_bounds() const
Returns the upper bounds values of all the bounding neurons in the layer.
const Tensor< type, 1 > & get_lower_bounds() const
Returns the lower bounds values of all the bounding neurons in the layer.
BoundingMethod bounding_method
Method used to bound the values.
void set_display(const bool &)
void write_XML(tinyxml2::XMLPrinter &) const
string write_bounding_method() const
Returns a string writing if use bounding layer or not.
void set_bounding_method(const BoundingMethod &)
void set_neurons_number(const Index &)
Tensor< type, 1 > upper_bounds
Upper bounds of output variables.
type get_lower_bound(const Index &) const
This abstract class represents the concept of layer of neurons in OpenNN.
Definition: layer.h:53
string layer_name
Layer name.
Definition: layer.h:179
Type layer_type
Layer type.
Definition: layer.h:183
XMLError QueryUnsignedAttribute(const char *name, unsigned int *value) const
See QueryIntAttribute()
Definition: tinyxml2.h:1328
const XMLElement * NextSiblingElement(const char *name=nullptr) const
Get the next(right) sibling element of this node, with an optionally supplied name.
Definition: tinyxml2.cpp:1059
void PushText(const char *text, bool cdata=false)
Add a text node.
Definition: tinyxml2.cpp:2878
void PushAttribute(const char *name, const char *value)
If streaming, add an attribute to an open element.
Definition: tinyxml2.cpp:2783
virtual void CloseElement(bool compactMode=false)
If streaming, close the Element.
Definition: tinyxml2.cpp:2834