RcsPySim
A robot control and simulation library
OMNormalized.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright (c) 2020, Fabio Muratore, Honda Research Institute Europe GmbH, and
3  Technical University of Darmstadt.
4  All rights reserved.
5 
6  Redistribution and use in source and binary forms, with or without
7  modification, are permitted provided that the following conditions are met:
8  1. Redistributions of source code must retain the above copyright
9  notice, this list of conditions and the following disclaimer.
10  2. Redistributions in binary form must reproduce the above copyright
11  notice, this list of conditions and the following disclaimer in the
12  documentation and/or other materials provided with the distribution.
13  3. Neither the name of Fabio Muratore, Honda Research Institute Europe GmbH,
14  or Technical University of Darmstadt, nor the names of its contributors may
15  be used to endorse or promote products derived from this software without
16  specific prior written permission.
17 
18  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  DISCLAIMED. IN NO EVENT SHALL FABIO MURATORE, HONDA RESEARCH INSTITUTE EUROPE GMBH,
22  OR TECHNICAL UNIVERSITY OF DARMSTADT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
26  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  POSSIBILITY OF SUCH DAMAGE.
29 *******************************************************************************/
30 
31 #include "OMNormalized.h"
32 
33 #include <stdexcept>
34 #include <sstream>
35 #include <cmath>
36 
37 static void
38 validateAndOverride(MatNd* bound, Rcs::PropertySource* override, const char* boundName, const Rcs::BoxSpace* space)
39 {
40  // Check each element
41  auto& names = space->getNames();
42  unsigned int nEle = bound->size;
43  for (unsigned int i = 0; i < nEle; ++i) {
44  auto bn = names[i];
45  // Try to load override
46  override->getProperty(bound->ele[i], bn.c_str());
47 
48  // Validate element is bounded now.
49  if (std::isinf(bound->ele[i])) {
50  std::ostringstream os;
51  os << bn << " entry of " << boundName
52  << " bound is infinite and not overridden. Cannot apply normalization.";
53  throw std::invalid_argument(os.str());
54  }
55  }
56 }
57 
59  Rcs::ObservationModel* wrapped, PropertySource* overrideMin, PropertySource* overrideMax) : wrapped(wrapped)
60 {
61  // Get inner model bounds with optional overrides
62  MatNd* iModMin = NULL;
63  MatNd* iModMax = NULL;
64  MatNd_clone2(iModMin, wrapped->getSpace()->getMin())
65  MatNd_clone2(iModMax, wrapped->getSpace()->getMax())
66 
67  validateAndOverride(iModMin, overrideMin, "lower", wrapped->getSpace());
68  validateAndOverride(iModMax, overrideMax, "upper", wrapped->getSpace());
69 
70  // Compute scale and shift from inner model bounds
71  // Shift is selected so that the median of min and max is 0
72  // shift = min + (max - min)/2
73  shift = MatNd_clone(iModMax);
74  MatNd_subSelf(shift, iModMin);
75  MatNd_constMulSelf(shift, 0.5);
76  MatNd_addSelf(shift, iModMin);
77 
78  // scale = (max - min)/2
79  scale = MatNd_clone(iModMax);
80  MatNd_subSelf(scale, iModMin);
81  MatNd_constMulSelf(scale, 0.5);
82 
83  // Cleanup temporary matrices
84  MatNd_destroy(iModMax);
85  MatNd_destroy(iModMin);
86 }
87 
89 {
90  // Free matrices
91  MatNd_destroy(shift);
92  MatNd_destroy(scale);
93 
94  delete wrapped;
95 }
96 
97 unsigned int Rcs::OMNormalized::getStateDim() const
98 {
99  return wrapped->getStateDim();
100 }
101 
103 {
104  return wrapped->getVelocityDim();
105 }
106 
107 void Rcs::OMNormalized::computeObservation(double* state, double* velocity, const MatNd* currentAction, double dt) const
108 {
109  // Query inner model
110  wrapped->computeObservation(state, velocity, currentAction, dt);
111 
112  // Normalize values
113  unsigned int sdim = getStateDim();
114  for (unsigned int i = 0; i < sdim; ++i) {
115  state[i] = (state[i] - shift->ele[i])/scale->ele[i];
116  }
117  for (unsigned int i = 0; i < getVelocityDim(); ++i) {
118  velocity[i] = (velocity[i] - shift->ele[i + sdim])/scale->ele[i + sdim];
119  }
120 }
121 
122 void Rcs::OMNormalized::getLimits(double* minState, double* maxState, double* maxVelocity) const
123 {
124  // query inner model
125  wrapped->getLimits(minState, maxState, maxVelocity);
126  // report actual scaled bounds, not explicit overrides
127  unsigned int sdim = getStateDim();
128  for (unsigned int i = 0; i < sdim; ++i) {
129  minState[i] = (minState[i] - shift->ele[i])/scale->ele[i];
130  maxState[i] = (maxState[i] - shift->ele[i])/scale->ele[i];
131  }
132  for (unsigned int i = 0; i < getVelocityDim(); ++i) {
133  maxVelocity[i] = (maxVelocity[i] - shift->ele[i + sdim])/scale->ele[i + sdim];
134  }
135 }
136 
138 {
139  wrapped->reset();
140 }
141 
142 std::vector<std::string> Rcs::OMNormalized::getStateNames() const
143 {
144  return wrapped->getStateNames();
145 }
146 
147 std::vector<std::string> Rcs::OMNormalized::getVelocityNames() const
148 {
149  return wrapped->getVelocityNames();
150 }
151 
152 std::vector<Rcs::ObservationModel*> Rcs::OMNormalized::getNested() const
153 {
154  return {wrapped};
155 }
ObservationModel * wrapped
Definition: OMNormalized.h:47
virtual void getLimits(double *minState, double *maxState, double *maxVelocity) const
virtual std::vector< std::string > getStateNames() const
virtual unsigned int getStateDim() const
const MatNd * getMin() const
Definition: BoxSpace.h:129
virtual std::vector< std::string > getStateNames() const
static void validateAndOverride(MatNd *bound, Rcs::PropertySource *override, const char *boundName, const Rcs::BoxSpace *space)
const BoxSpace * getSpace() const
virtual void computeObservation(double *state, double *velocity, const MatNd *currentAction, double dt) const
virtual std::vector< std::string > getVelocityNames() const
virtual std::vector< ObservationModel * > getNested() const
MatNd * computeObservation(const MatNd *currentAction, double dt) const
const MatNd * getMax() const
Definition: BoxSpace.h:137
virtual unsigned int getVelocityDim() const
OMNormalized(ObservationModel *wrapped, PropertySource *overrideMin, PropertySource *overrideMax)
virtual unsigned int getStateDim() const =0
virtual unsigned int getVelocityDim() const
virtual void getLimits(double *minState, double *maxState, double *maxVelocity) const
virtual ~OMNormalized()
virtual void reset()
virtual std::vector< std::string > getVelocityNames() const
const std::vector< std::string > & getNames() const
Definition: BoxSpace.h:147