Skip to content

Instantly share code, notes, and snippets.

@2bbb
Last active January 6, 2016 14:31
Show Gist options
  • Select an option

  • Save 2bbb/24395df49f027c75c11e to your computer and use it in GitHub Desktop.

Select an option

Save 2bbb/24395df49f027c75c11e to your computer and use it in GitHub Desktop.
linear regression study
#include "ofMain.h"
namespace linear_regression {
using default_value_type = float;
template <std::size_t num, typename value_type = default_value_type>
struct model {
using record = std::array<value_type, num>;
using result = value_type;
using datum = std::pair<record, result>;
using data = std::vector<datum>;
using offset = value_type;
using weight = std::array<value_type, num>;
using parameter = std::pair<offset, weight>;
static inline result prediction(const parameter &p, const datum &m) {
result sum{p.first};
for(std::size_t i = 0; i < m.first.size(); i++) sum += p.second[i] * m.first[i];
return sum;
}
static inline result error(const parameter &p, const datum &m) {
return pow(m.second - prediction(p, m), static_cast<value_type>(2.0f));
}
static inline result objective(const parameter &p, const data &d) {
result sum{0.0};
std::for_each(d.begin(), d.end(), [&](datum &m){ sum += error(p, m); });
return sum;
}
static inline result d_offset(const parameter &p, const datum &m) {
return 2.0 * (prediction(p, m) - m.second);
}
static inline result d_record(const parameter &p, const datum &m, std::size_t index) {
return 2.0 * m.first[index] * (prediction(p, m) - m.second);
}
static inline parameter step(const parameter &p, const data &d, float scale = 0.01f) {
const datum &m = d[rand() % d.size()];
parameter p0{p};
p0.first -= d_offset(p, m) * scale;
for(std::size_t i = 0; i < p0.second.size(); i++) p0.second[i] -= d_record(p, m, i) * scale;
return p0;
}
};
};
class ofApp : public ofBaseApp {
using model = linear_regression::model<1>;
model::data data;
model::parameter p;
public:
void setup() {
p = {ofRandom(1.0f), {ofRandom(1.0f)}};
float a = ofRandom(-1.0f, 1.0f), b = ofRandom(0.5f);
for(std::size_t i = 0; i < 1000; i++) {
model::datum d;
d.first[0] = ofRandom(1.0f);
d.second = a * (d.first[0] + ofRandom(-0.03, 0.03)) + b;
data.push_back(d);
}
}
void update() {
p = model::step(p, data);
}
void draw() {
ofTranslate(0, ofGetHeight());
ofScale(1, -1);
ofBackground(0, 0, 0);
ofSetColor(255, 255, 255);
for(auto &d : data) {
ofDrawCircle(720 * d.first[0], 720 * d.second, 1);
}
ofSetColor(255, 0, 0);
ofDrawLine(0, p.first * 720, 720, (p.first + p.second[0]) * 720);
}
};
int main() {
ofSetupOpenGL(720, 720, OF_WINDOW);
ofRunApp(new ofApp);
}
#include "ofMain.h"
namespace linear_regression {
using default_value_type = float;
template <std::size_t num, typename value_type = default_value_type>
struct model {
using record = std::array<value_type, num>;
using result = value_type;
using datum = std::pair<record, result>;
using data = std::vector<datum>;
using offset = value_type;
using weight = std::array<value_type, num>;
using parameter = std::pair<offset, weight>;
static inline result prediction(const parameter &p, const datum &m) {
result sum{p.first};
for(std::size_t i = 0; i < m.first.size(); i++) sum += p.second[i] * m.first[i];
return sum;
}
static inline result error(const parameter &p, const datum &m) {
return pow(m.second - prediction(p, m), static_cast<value_type>(2.0f));
}
static inline result objective(const parameter &p, const data &d) {
result sum{0.0};
std::for_each(d.begin(), d.end(), [&](datum &m){ sum += error(p, m); });
return sum;
}
static inline result d_offset(const parameter &p, const datum &m) {
return 2.0 * (prediction(p, m) - m.second);
}
static inline result d_record(const parameter &p, const datum &m, std::size_t index) {
return 2.0 * m.first[index] * (prediction(p, m) - m.second);
}
static inline parameter step(const parameter &p, const data &d, float scale = 0.01f) {
const datum &m = d[rand() % d.size()];
parameter p0{p};
p0.first -= d_offset(p, m) * scale;
for(std::size_t i = 0; i < p0.second.size(); i++) p0.second[i] -= d_record(p, m, i) * scale;
return p0;
}
};
};
class ofApp3D : public ofBaseApp {
using model = linear_regression::model<2>;
model::data data;
model::parameter p;
unsigned long long startFrame{0};
float fov{30};
ofEasyCam cam;
ofVec3f target;
public:
void setup() {
p = {ofRandom(1.0f), {ofRandom(1.0f), ofRandom(1.0f)}};
float a = ofRandom(-1.0f, 1.0f), b = ofRandom(-1.0f, 1.0f), c = ofRandom(0.5f);
for(std::size_t i = 0; i < 1000; i++) {
model::datum d;
d.first[0] = ofRandom(-1.0f, 1.0f);
d.first[1] = ofRandom(-1.0f, 1.0f);
d.second = a * (d.first[0] + ofRandom(-0.1, 0.1)) + b * (d.first[1] + ofRandom(-0.1, 0.1)) + c;
data.push_back(d);
}
cam.setFov(fov);
cam.setTarget(ofVec3f(0, 0, 0));
}
void update() {
if(ofGetFrameNum() % 100 == 0) {
float theta = ofRandom(M_PI * 2), phi = ofRandom(M_PI);
target.set(cos(theta) * cos(phi) * 360.0f, sin(theta) * cos(phi) * 360.0f, sin(phi) * 360.0f);
fov = ofRandom(30, 150);
} else {
cam.setFov(ofLerp(cam.getFov(), fov, 0.1f));
cam.setPosition(cam.getPosition().interpolate(target, 0.1f));
cam.setTarget(ofVec3f(0, 0, 0));
}
p = model::step(p, data);
}
void draw() {
cam.begin();
ofBackground(0, 0, 0);
ofSetColor(255, 255, 255);
ofEnableDepthTest();
for(auto &d : data) {
ofDrawSphere(d.first[0] * 360, d.second * 360, d.first[1] * 360, 2);
}
for(int i = -36; i <= 36; i++) {
ofSetColor(255, 0, 0);
ofDrawLine(-360, 360 * (p.first - p.second[0] + p.second[1] * i / 36.0f), i * 10,
360, 360 * (p.first + p.second[0] + p.second[1] * i / 36.0f), i * 10);
ofSetColor(0, 255, 0);
ofDrawLine(i * 10, 360 * (p.first + p.second[0] * i / 36.0f - p.second[1]), -360,
i * 10, 360 * (p.first + p.second[0] * i / 36.0f + p.second[1]), 360);
}
ofDisableDepthTest();
cam.end();
}
void keyPressed(int key) {
startFrame = ofGetFrameNum();
if(key == 'r') {
data.clear();
setup();
}
}
};
int main() {
ofSetupOpenGL(720, 720, OF_WINDOW);
ofRunApp(new ofApp3D);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment