diff --git a/7/7-1.c b/7/7-1.c new file mode 100644 index 0000000..a0005e0 --- /dev/null +++ b/7/7-1.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include + +// SOLUTION USING GRADIENT DESCENT + +#define PART_2 + +#ifdef PART_2 +#define STEP 0.0001F +#else +#define STEP 0.2F +#endif + +#define INITIAL_CONDITION \ + { \ + 16, 1, 2, 0, 4, 2, 7, 1, 2, 14 \ + } +#define INITIAL_GUESS 10000.0F + +// THIS IS NEEDED FOR PART 2 BECAUSE OF FLOATS. QUICK AND DIRTY COPYPASTE. +int fuel_total_int(int *state, size_t state_len, int point) +{ + int total = 0; + for (size_t i = 0; i < state_len; i++) + { + int fuel = abs(state[i] - point); +#ifdef PART_2 + fuel *= (fuel + 1) / 2.0F; // TRIANGLE NUMBER T_n = n/2*(n+1) +#endif + total += fuel; + } + return total; +} + +// MUST BE FLOAT FOR GRADIENT DESCENT TO WORK. +float fuel_total(int *state, size_t state_len, float point) +{ + float total = 0; + for (size_t i = 0; i < state_len; i++) + { + float fuel = fabs(state[i] - point); +#ifdef PART_2 + fuel *= (fuel + 1) / 2.0F; // TRIANGLE NUMBER T_n = n/2*(n+1) +#endif + total += fuel; + } + return total; +} + +void gradient_descent(int *state, size_t state_len, float *guess, float *gradient) +{ + float y = fuel_total(state, state_len, *guess); + float dy_dx = fuel_total(state, state_len, *guess + 1) - y; + printf("%.5f, y=%.5f, dy=%.5f\n", *guess, y, dy_dx); + *guess -= STEP * dy_dx; + *gradient = dy_dx; +} + +float main(float argc, char const *argv[]) +{ + int state[] = INITIAL_CONDITION; + size_t state_len = sizeof(state) / sizeof(state[0]); + float guess = INITIAL_GUESS; + float gradient = 1.0F; // START WITH NON-ZERO VALUE + while (fabs(gradient) > 0.01) + { + gradient_descent(state, state_len, &guess, &gradient); + } + + // CHECK "AREA" SURROUNDING FINAL GUESS + int min_fuel = __INT_MAX__; + for (int t = guess - 1; t < guess + 1; t++) + { + int fuel = fuel_total_int(state, state_len, t); + if (fuel < min_fuel) + min_fuel = fuel; + } + + printf("FUEL %d\n", (int)min_fuel); + + return 0; +}