|
version 1.14, 2005/02/16 21:17:10
|
version 1.15, 2005/02/17 08:01:32
|
|
|
|
| #include <stack> | #include <stack> |
| #include <vector> | #include <vector> |
| #include <stdio.h> | #include <stdio.h> |
| // yes I could use just one i/o lib |
|
| using namespace std; |
|
| |
|
| |
|
| // As per specification, the project has to be able to grow to an |
|
| // arbitrary amount of items. MAX_ITEMS describes the size of the |
|
| // appropriate arrays and must be changed at compile time. |
|
| // (dynamically created arrays had their pointers corrupted when |
|
| // their parent object was in the priority queue, so static sized |
|
| // arrays were used |
|
| | |
| #define MAX_ITEMS 65536 |
using namespace std; |
| //the above bound comes from the fixed value for the boolean array TODO REMOVE LIMITATION |
|
| | |
| #define EARLYSKIP |
//threading might be useful except for the fact that our target machine is likely to have a single processor |
| |
// what about task limiting from SEAS? |
| |
// actually sparc machines on ugrad are multiple processor -- could I thread/fork the calculations? would overhead > savings |
| |
// also if i was really stingy, I could revert to the arrays I had before, make them dynamic and create a copy ctor for key |
| |
// of course, vector<bool> packs 8 bools in a byte, arrays dont |
| | |
| typedef long ITEM_MASS; | typedef long ITEM_MASS; |
| typedef long INDEX_TYPE; | typedef long INDEX_TYPE; |
|
|
|
| // * CLASS : item * | // * CLASS : item * |
| // * Container object with all the data for a particular item * | // * Container object with all the data for a particular item * |
| // ****************************************************************** | // ****************************************************************** |
| |
|
| |
//since items are no longer special in any way, I could actually just use a vector now! |
| |
// would this be any faster? |
| |
|
| class item { | class item { |
| public: | public: |
| // float getRatio(); |
|
| ITEM_MASS getWeight(); | ITEM_MASS getWeight(); |
| // ITEM_MASS getNumber(); |
|
| void setData(ITEM_MASS); | void setData(ITEM_MASS); |
| private: | private: |
| ITEM_MASS weight; | ITEM_MASS weight; |
| // float ratio; |
|
| // ITEM_MASS number; |
|
| }; | }; |
| | |
| // ****************************************************************** | // ****************************************************************** |
|
|
|
| void flagNext(); | void flagNext(); |
| void addCurItem(); | void addCurItem(); |
| bool doneItems(); | bool doneItems(); |
| float getBound(); |
ITEM_MASS getBound(); |
| bool checkItem(INDEX_TYPE); | bool checkItem(INDEX_TYPE); |
| ITEM_MASS getWeight(); | ITEM_MASS getWeight(); |
| void makeDone(); |
|
| private: | private: |
| void calcBound(); | void calcBound(); |
| bool inserted[MAX_ITEMS]; |
vector<bool> inserted; |
| |
// replace with a vector! this allows us to remove MAX_ITEMS without the fussyness of copying the |
| |
// contents of a pointer etc like before! |
| |
// bool inserted[MAX_ITEMS]; |
| INDEX_TYPE nextitem; | INDEX_TYPE nextitem; |
| ITEM_MASS cur_weight; | ITEM_MASS cur_weight; |
| float upper_bound; |
ITEM_MASS upper_bound; |
| backpack *myBackpack; | backpack *myBackpack; |
| }; | }; |
| | |
|
|
|
| struct item_comparator { | struct item_comparator { |
| bool operator()( item left, item right ) const | bool operator()( item left, item right ) const |
| // { return ( left.getRatio() < right.getRatio() ) ; } | // { return ( left.getRatio() < right.getRatio() ) ; } |
| { return 0 ; } //same ratio to all, don't actually do a compare! |
// { return ( left.getWeight() < right.getWeight() ); } |
| |
{return 0;} |
| |
// larger boxes are preferable to smaller boxes |
| |
// removes the need for sort at beginning. |
| |
// this actually massively increases the time cost for my sample set. defaulting to dumb sort |
| } ; | } ; |
| | |
| // ****************************************************************** | // ****************************************************************** |
|
|
|
| class backpack { | class backpack { |
| public: | public: |
| void initBackpack(INDEX_TYPE, ITEM_MASS); | void initBackpack(INDEX_TYPE, ITEM_MASS); |
| |
void changeBackpack(INDEX_TYPE); |
| void putItem(ITEM_MASS);//, ITEM_MASS); | void putItem(ITEM_MASS);//, ITEM_MASS); |
| void store_item_array(); | void store_item_array(); |
| void branch_and_bound(int,ITEM_MASS); | void branch_and_bound(int,ITEM_MASS); |
|
|
|
| this->nextitem=0; | this->nextitem=0; |
| this->cur_weight=0; | this->cur_weight=0; |
| this->calcBound(); | this->calcBound(); |
| for ( int i = 0; MAX_ITEMS > i; i++) { |
|
| this->inserted[i] = 0; |
|
| } |
|
| } | } |
| | |
| // ****************************************************************** | // ****************************************************************** |
|
|
|
| // * as processed, then updates the bound. * | // * as processed, then updates the bound. * |
| // ****************************************************************** | // ****************************************************************** |
| void key::flagNext(){ | void key::flagNext(){ |
| this->inserted[this->nextitem]= 0; |
// this->inserted[this->nextitem]= 0; |
| |
this->inserted.push_back(0); |
| nextitem++; | nextitem++; |
| this->calcBound(); | this->calcBound(); |
| } | } |
|
|
|
| // ****************************************************************** | // ****************************************************************** |
| void key::addCurItem(){ | void key::addCurItem(){ |
| nextitem--; | nextitem--; |
| this->inserted[this->nextitem]=1; |
this->inserted.push_back(1); |
| |
// this->inserted[this->nextitem]=1; |
| this->cur_weight += (this->myBackpack->get_Item(this->nextitem)).getWeight(); | this->cur_weight += (this->myBackpack->get_Item(this->nextitem)).getWeight(); |
| nextitem++; | nextitem++; |
| this->calcBound(); | this->calcBound(); |
|
|
|
| return ( this->myBackpack->get_totalItems() == this->nextitem ); | return ( this->myBackpack->get_totalItems() == this->nextitem ); |
| } | } |
| | |
| void key::makeDone(){ |
|
| this->nextitem = this->myBackpack->get_totalItems(); |
|
| } |
|
| |
|
| // ****************************************************************** | // ****************************************************************** |
| // * FUNCTION : getBound IN : CLASS key * | // * FUNCTION : getBound IN : CLASS key * |
| // * Returns the bound. * | // * Returns the bound. * |
| // ****************************************************************** | // ****************************************************************** |
| float key::getBound(){ |
ITEM_MASS key::getBound(){ |
| return this->upper_bound; | return this->upper_bound; |
| } | } |
| | |
|
|
|
| } | } |
| else { | else { |
| temp = ((this->myBackpack->get_maxWeight()) - cur_weight); | temp = ((this->myBackpack->get_maxWeight()) - cur_weight); |
| // temp = temp * (this->myBackpack->get_Item(this->nextitem)).getRatio(); (ratio = 1!) |
|
| } | } |
| this->upper_bound = cur_weight + temp; | this->upper_bound = cur_weight + temp; |
| | |
|
|
|
| } | } |
| | |
| // ****************************************************************** | // ****************************************************************** |
| // * FUNCTION : getValue IN : CLASS key * |
|
| // * Gets the Value of the current key. * |
|
| // ****************************************************************** |
|
| //ITEM_MASS key::getValue(){ |
|
| // return this->cur_value; |
|
| //} |
|
| |
|
| // ****************************************************************** |
|
| // * FUNCTION : getWeight IN : CLASS key * | // * FUNCTION : getWeight IN : CLASS key * |
| // * Gets the Weight of the current key. * | // * Gets the Weight of the current key. * |
| // ****************************************************************** | // ****************************************************************** |
|
|
|
| } | } |
| | |
| // ****************************************************************** | // ****************************************************************** |
| // * FUNCTION : getRatio IN : CLASS item * |
|
| // * Gets the Ratio for the current item. * |
|
| // ****************************************************************** |
|
| //float item::getRatio(){ |
|
| // return ratio; |
|
| //} |
|
| |
|
| // ****************************************************************** |
|
| // * FUNCTION : getWeight IN : CLASS item * | // * FUNCTION : getWeight IN : CLASS item * |
| // * Gets the Weight of the current item. * | // * Gets the Weight of the current item. * |
| // ****************************************************************** | // ****************************************************************** |
|
|
|
| return this->weight; | return this->weight; |
| } | } |
| | |
| // ****************************************************************** |
|
| // * FUNCTION : getCost IN : CLASS item * |
|
| // * Gets the Value of the current item. * |
|
| // ****************************************************************** |
|
| ///ITEM_MASS item::getCost(){ |
|
| /// return this->cost; |
|
| ///} |
|
| |
|
| // ****************************************************************** |
|
| // * FUNCTION : getNumber IN : CLASS item * |
|
| // * Gets the Index of the current item. * |
|
| // ****************************************************************** |
|
| //ITEM_MASS item::getNumber(){ |
|
| // return this->number; |
|
| //} |
|
| | |
| // ****************************************************************** | // ****************************************************************** |
| // * FUNCTION : setData IN : CLASS item * | // * FUNCTION : setData IN : CLASS item * |
|
|
|
| // * Initalizes the backpack values and creates the item array * | // * Initalizes the backpack values and creates the item array * |
| // ****************************************************************** | // ****************************************************************** |
| void backpack::initBackpack(INDEX_TYPE total, ITEM_MASS max){ | void backpack::initBackpack(INDEX_TYPE total, ITEM_MASS max){ |
| this->totalItems = total; |
|
| this->maxWeight = max; | this->maxWeight = max; |
| |
this->totalItems = total; |
| item_array = new item[total]; | item_array = new item[total]; |
| worknodeCount = 0; | worknodeCount = 0; |
| addnodeCount = 0; | addnodeCount = 0; |
| } | } |
| | |
| |
|
| |
|
| // ****************************************************************** | // ****************************************************************** |
| // * FUNCTION : putItem IN : CLASS backpack * | // * FUNCTION : putItem IN : CLASS backpack * |
| // * Creates an item and places it into the priority queue * | // * Creates an item and places it into the priority queue * |
|
|
|
| this->key_queue.pop(); | this->key_queue.pop(); |
| /*Early skip here -- MASSIVE speed improvements */ | /*Early skip here -- MASSIVE speed improvements */ |
| if ( temp_key.getWeight() == targetvalue ) { | if ( temp_key.getWeight() == targetvalue ) { |
| printf("Early value acquired! %d\n",temp_key.getWeight() ); |
//printf("Early value acquired! %d\n",temp_key.getWeight() ); |
| goto early; // yes thats a go to. Its the only way to leave and keep the context right. I know its horrible | goto early; // yes thats a go to. Its the only way to leave and keep the context right. I know its horrible |
| } | } |
| |
// printf("reached %d\n",temp_key.getWeight()); |
| if ( temp_key.doneItems() ) { | if ( temp_key.doneItems() ) { |
| onwards = 0; | onwards = 0; |
| } | } |
| else { | else { |
| this->worknodeCount++; |
// this->worknodeCount++; |
| temp_key.flagNext(); | temp_key.flagNext(); |
| this->key_queue.push(temp_key); | this->key_queue.push(temp_key); |
| this->addnodeCount++; |
// this->addnodeCount++; |
| |
|
| | |
| // try this --- compare quicksorted before and after because of greedy grabbing largest | // try this --- compare quicksorted before and after because of greedy grabbing largest |
| //should find other comparator for weight with sub data like ... pct done | //should find other comparator for weight with sub data like ... pct done |
| | |
| |
|
| |
|
| |
|
| temp_key.addCurItem(); | temp_key.addCurItem(); |
| if (temp_key.getBound() != 0){ |
if (temp_key.getBound() != 0){ //insert only if active. |
| this->key_queue.push(temp_key); | this->key_queue.push(temp_key); |
| this->addnodeCount++; |
// this->addnodeCount++; |
| } | } |
| } | } |
| // if ((this->addnodeCount % 1000) == 0) {printf("10000!");} |
// commenting out worknode trackerincreases speed by 3% |
| } | } |
| while (onwards); | while (onwards); |
| | |
| early: if (DEBUG_MODE) { | early: if (DEBUG_MODE) { |
| printf("Case n=%2d Total possible nodes in thie state space tree is 2^%2d-1\n",this->totalItems,this->totalItems); | printf("Case n=%2d Total possible nodes in thie state space tree is 2^%2d-1\n",this->totalItems,this->totalItems); |
| printf(" Number of nodes placed in the priority queue: %6d\n",this->addnodeCount); |
printf(" DISABLED Number of nodes placed in the priority queue: %6d\n",this->addnodeCount); |
| printf(" Number of nodes examined/split: %6d\n",this->worknodeCount); |
printf(" DISABLED Number of nodes examined/split: %6d\n",this->worknodeCount); |
| /* printf("\nObjects Chosen \n"); |
|
| |
|
| printf("\t\tWeights\tValues\n"); |
|
| int totalitemsinserted = 0; |
|
| for (int i = 0; this->totalItems > i; i++) { |
|
| if ( temp_key.checkItem(i) ) { |
|
| printf("\t\t%4.2f\t%4.2f\n", this->item_array[i].getWeight(), this->item_array[i].getCost()); |
|
| totalitemsinserted++; // this->item_array[i].getNumber(), removed |
|
| } |
|
| } |
|
| printf("======================================================\n"); |
|
| printf("Totals:\t%3d\t%4.2f\t%4.2f\n",totalitemsinserted, temp_key.getWeight(), temp_key.getValue()); |
|
| // printf("Ratio : %2.5f\n", ((float)temp_key.getValue()/(float)temp_key.getWeight())); */ |
|
| } | } |
| | |
| |
|
| if ( temp_key.getWeight() == targetvalue ) { | if ( temp_key.getWeight() == targetvalue ) { |
| int totalitemsinserted = 0; | int totalitemsinserted = 0; |
| int first=1; | int first=1; |
|
|
|
| else { printf("CANNOT FILL PALLET\n"); } | else { printf("CANNOT FILL PALLET\n"); } |
| } | } |
| | |
| // have to deal with non int #s |
void super_increase_algo ( vector<ITEM_MASS> inventory, ITEM_MASS target_value , int DEBUG_MODE ) { |
| |
|
| void super_increase_algo ( vector<ITEM_MASS> inventory, ITEM_MASS target_value , INDEX_TYPE size_inventory, int DEBUG_MODE ) { |
|
| stack<ITEM_MASS> packages_to_load; | stack<ITEM_MASS> packages_to_load; |
| |
INDEX_TYPE size_inventory = inventory.size(); |
| | |
| if (DEBUG_MODE) { | if (DEBUG_MODE) { |
| printf("Extracting values, highest to lowest, doing reduction from index %d\n",size_inventory); | printf("Extracting values, highest to lowest, doing reduction from index %d\n",size_inventory); |
|
|
|
| printf("All compiled / source code are (C) Rizwan Kassim 2005\n\n"); | printf("All compiled / source code are (C) Rizwan Kassim 2005\n\n"); |
| } | } |
| | |
| |
|
| INDEX_TYPE max_inventory; |
|
| |
|
| ifstream inputfs; | ifstream inputfs; |
| inputfs.open (argv[1]); | inputfs.open (argv[1]); |
| if (!inputfs.is_open()) | if (!inputfs.is_open()) |
|
|
|
| theToken = strtok (NULL,","); | theToken = strtok (NULL,","); |
| } | } |
| | |
| INDEX_TYPE size_inventory = inventory.size(); //remember this is 1 based, not 0 |
|
| | |
| int SUPER_MODE = 0; | int SUPER_MODE = 0; |
| if (inventory[0]==1) { SUPER_MODE=1;} | if (inventory[0]==1) { SUPER_MODE=1;} |
| | |
| if (DEBUG_MODE) { | if (DEBUG_MODE) { |
| printf("Line 1 read - %d products from warehouse\n", size_inventory); |
printf("Line 1 read - %d products from warehouse\n", inventory.size()); |
| if (SUPER_MODE) printf("Working in Superincreasing mode!\n"); | if (SUPER_MODE) printf("Working in Superincreasing mode!\n"); |
| } | } |
| | |
| // qsort ( inventory, size_inventory, sizeof(ITEM_MASS), masscomp); // we now have a sorted list |
|
| // sort (inventory.begin(), inventory.end(),std::greater<ITEM_MASS>() ); | // sort (inventory.begin(), inventory.end(),std::greater<ITEM_MASS>() ); |
| sort (inventory.begin(), inventory.end()); |
// sort (inventory.begin(), inventory.end()); // most efficient, uses largest boxes inherently |
| // sorts array in reverse order, biggest elements first ( |
|
| // NEED TRY/CATCH error handling for possible segfault locations | // NEED TRY/CATCH error handling for possible segfault locations |
| inputfs.getline (read_buffer, length-1); | inputfs.getline (read_buffer, length-1); |
| ITEM_MASS palette_size=atoi(read_buffer); |
ITEM_MASS palette_size=atol(read_buffer); |
| | |
| if (DEBUG_MODE) { | if (DEBUG_MODE) { |
| printf("Line 2 read - %d weight units can fit onto palette\n",palette_size); | printf("Line 2 read - %d weight units can fit onto palette\n",palette_size); |
| } | } |
| | |
| |
inputfs.close(); |
| |
free(read_buffer); |
| |
|
| |
|
| |
// I could use a class to extrapolate out the file loading function like my 499 project.... |
| |
|
| |
|
| if (SUPER_MODE) { | if (SUPER_MODE) { |
| super_increase_algo (inventory, palette_size , size_inventory, DEBUG_MODE ); |
super_increase_algo (inventory, palette_size , DEBUG_MODE ); |
| return 0; | return 0; |
| } | } |
| | |
| inputfs.close(); |
// filter out oversizes BEFORE we insert them above, therefore making life complicated |
| free(read_buffer); |
|
| | |
| // I could use a class to extrapolate out the file loading function like my 499 project.... |
vector<ITEM_MASS>::iterator itInventory; |
| |
|
| |
// printf("inventory before %d\n",inventory.size()); |
| |
for(itInventory = inventory.begin(); itInventory != inventory.end(); itInventory++) { |
| |
if (*itInventory > palette_size ) { |
| |
// printf("%d removing at , left %d!\n",*itInventory,inventory.size()); |
| |
inventory.erase(itInventory); |
| |
itInventory--; |
| |
// printf("%d removed at %d, left!\n",*itInventory,inventory.size()); |
| |
// remove elements that are too large. its a n increase here, but >>n increase if done later |
| |
} |
| |
} |
| | |
| backpack knapsackOne; | backpack knapsackOne; |
| | |
| knapsackOne.initBackpack(size_inventory,palette_size); |
knapsackOne.initBackpack(inventory.size(),palette_size); |
| if (DEBUG_MODE) { | if (DEBUG_MODE) { |
| printf("init %d, %d\n",size_inventory,palette_size); |
printf("init %d, %d\n",inventory.size(),palette_size); |
| } | } |
| for ( INDEX_TYPE store_index=0; size_inventory>store_index;store_index++ ) { |
|
| knapsackOne.putItem(inventory[store_index]); |
|
| | |
| if (DEBUG_MODE) { |
for(itInventory = inventory.begin(); itInventory != inventory.end(); itInventory++) { |
| printf("insert %d\n",inventory[store_index]); |
knapsackOne.putItem(*itInventory); |
| |
// if (DEBUG_MODE) { |
| |
// printf("insert %d\n",*itInventory); |
| |
// } |
| } | } |
| | |
| } |
|
| knapsackOne.store_item_array(); | knapsackOne.store_item_array(); |
| inventory.clear(); | inventory.clear(); |
| |
|
| knapsackOne.branch_and_bound(DEBUG_MODE,palette_size); | knapsackOne.branch_and_bound(DEBUG_MODE,palette_size); |
| | |
| printf("\n"); | printf("\n"); |
|
|
|
| | |
| with presort and early out | with presort and early out |
| | |
| |
with sort and weight based item compare |
| |
|
| |
|
| |
with item based compare |
| |
real 0m2.676s |
| |
user 0m2.499s |
| |
sys 0m0.108s |
| |
|
| |
item based compare AND sort |
| |
real 0m2.543s |
| |
user 0m2.452s |
| |
sys 0m0.062s |
| |
|
| |
|
| */ | */ |
| | |