/***************************************************************************
 *   Copyright (C) 2007 by Honorius Galmeanu                               *
 *   honorius_galmeanu@yahoo.com                                           *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 *                                                                         *
 *   Copyright: See COPYING file that comes with this distribution         *
 *                                                                         *
 ***************************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "idcommon.h"
#include "idsvmr.h"


void x_svm_r::save_state (x_vector<int>& perm, char * file_name)
{
	long nr = 0, idx = 0;
	double lambda = 0, h = 0;
	char type = 'Z';

	FILE * f = fopen (file_name, "wb");
	if (!f) { TRACE ("cannot open file %s", file_name); exit (1); }

	// header
	char signature [] = "idsvmr-state";
	fwrite (signature, sizeof (signature), 1, f);

	// C parameter
	lambda = param.C;
	fwrite (&lambda, sizeof (lambda), 1, f);

	// support vectors
	nr = s_vect.len ();
	fwrite (&nr, sizeof (nr), 1, f);
	for (int i = 0 ; i < s_vect.len () ; i ++)
	{
		idx = s_vect[i].idx;
		lambda = s_vect[i].lambda;
		type = 'U';
		h = calc_h (idx);

		fwrite (&idx, sizeof (idx), 1, f);
		fwrite (&lambda, sizeof (lambda), 1, f);
		fwrite (&type, sizeof (type), 1, f);
		fwrite (&h, sizeof (h), 1, f);
	}
	
	// rest vectors
 	nr = r_vect.len ();
 	fwrite (&nr, sizeof (nr), 1, f);
 	for (int i = 0 ; i < r_vect.len () ; i ++)
 	{
 		idx = r_vect[i].idx;
 		lambda = r_vect[i].lambda;
 		type = r_vect[i].type == x_elem::ZERO ? 'Z' : 'B';
 		h = calc_h (idx);
 
 		fwrite (&idx, sizeof (idx), 1, f);
 		fwrite (&lambda, sizeof (lambda), 1, f);
 		fwrite (&type, sizeof (type), 1, f);
 		fwrite (&h, sizeof (h), 1, f);
 	}

	// w0
	lambda = w0;
	fwrite (&lambda, sizeof (lambda), 1, f);

// 	// P
// 	nr = p.len ();
// 	fwrite (&nr, sizeof (nr), 1, f);
// 	for (int i = 0 ; i < p.len () ; i ++)
// 		fwrite (p[i], sizeof (double), p.len (), f);
// 
// 	// and Q
// 	nr = q.len ();
// 	fwrite (&nr, sizeof (nr), 1, f);
// 	for (int i = 0 ; i < q.len () ; i ++)
// 		fwrite (q[i], sizeof (double), q.len (), f);

	// perm
	perm.store (f);

	fclose (f);
}


void x_svm_r::restore_state (x_vector<int>& perm, char * file_name)
{
	long nr = 0, idx = 0;
	double lambda = 0, h = 0;
	char type = 'Z';

	FILE * f = fopen (file_name, "rb");
	if (!f) { TRACE ("cannot open file %s", file_name); exit (1); }

	char signature [] = "idsvmr-state";
	fread (signature, sizeof (signature), 1, f);
	if (strcmp (signature, "idsvmr-state"))
	{
		TRACE ("invalid file - header unrecognized");
		exit (1);
	}

	fread (&lambda, sizeof (lambda), 1, f);
	param.C = lambda;

	fread (&nr, sizeof (nr), 1, f);
	if (nr < 0 || nr > 1000000) { TRACE ("invalid file"); exit (1); }
	s_vect.ensure (nr);
	for (int i = 0 ; i < s_vect.len () ; i ++)
	{
		fread (&idx, sizeof (idx), 1, f);
		fread (&lambda, sizeof (lambda), 1, f);
		fread (&type, sizeof (type), 1, f);
		fread (&h, sizeof (h), 1, f);

		if (idx < 0 || idx > 1000000) { TRACE ("invalid file: %ld", idx); exit (1); }
		s_vect[i].idx = idx;
		s_vect[i].lambda = lambda;
		s_vect[i].type = x_elem::UNBOUNDED;

		if (type != 'U') { TRACE ("invalid file"); exit (1); }
	}

	fread (&nr, sizeof (nr), 1, f);
	if (nr < 0 || nr > 1000000) { TRACE ("invalid file"); exit (1); }
	r_vect.ensure (nr);
	for (int i = 0 ; i < r_vect.len () ; i ++)
	{
		fread (&idx, sizeof (idx), 1, f);
		fread (&lambda, sizeof (lambda), 1, f);
		fread (&type, sizeof (type), 1, f);
		fread (&h, sizeof (h), 1, f);
 
		if (idx < 0 || idx > 1000000) { TRACE ("invalid file: %ld", idx); exit (1); }
		r_vect[i].idx = idx;
		r_vect[i].lambda = lambda;
 
		r_vect[i].type = (type == 'Z' ? x_elem::ZERO : x_elem::BOUNDED);
		if (type == 'Z' && !IS_ZERO (lambda)) { TRACE ("invalid file"); exit (1); }
		if (type == 'B' && IS_ZERO (lambda)) { TRACE ("invalid file"); exit (1); }
		if (type == 'U') { TRACE ("invalid file"); exit (1); }
	}

	// w0
	fread (&lambda, sizeof (lambda), 1, f);
	w0 = lambda;

	// now test gradients
	rewind (f);
	fread (signature, sizeof (signature), 1, f);
	fread (&lambda, sizeof (lambda), 1, f);

	fread (&nr, sizeof (nr), 1, f);
	for (int i = 0 ; i < s_vect.len () ; i ++)
	{
		fread (&idx, sizeof (idx), 1, f);
		fread (&lambda, sizeof (lambda), 1, f);
		fread (&type, sizeof (type), 1, f);
		fread (&h, sizeof (h), 1, f);

		if (h != calc_h (idx)) { TRACE ("gradients differ: %ld, actual %g /saved %g", idx, calc_h(idx), h); exit (1); }
	}

	fread (&nr, sizeof (nr), 1, f);
	for (int i = 0 ; i < r_vect.len () ; i ++)
	{
		fread (&idx, sizeof (idx), 1, f);
		fread (&lambda, sizeof (lambda), 1, f);
		fread (&type, sizeof (type), 1, f);
		fread (&h, sizeof (h), 1, f);

		if (h != calc_h (idx)) { TRACE ("gradients differ: %ld, actual %g /saved %g", idx, calc_h(idx), h); exit (1); }
	}

	// w0
	fread (&lambda, sizeof (lambda), 1, f);

// 	// P
// 	fread (&nr, sizeof (nr), 1, f);
// 	p.ensure (nr);
// 	for (int i = 0 ; i < p.len () ; i ++)
// 		fread (p[i], sizeof (double), p.len (), f);
// 
// 	// and Q
// 	fread (&nr, sizeof (nr), 1, f);
// 	q.ensure (nr);
// 	for (int i = 0 ; i < q.len () ; i ++)
// 		fread (q[i], sizeof (double), q.len (), f);

	// perm
	perm.restore (f);
	fclose (f);

	regenerate_pq ();
}
